package mysql

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
	"github.com/fleetdm/fleet/v4/server/fleet"
	"github.com/fleetdm/fleet/v4/server/mdm"
	"github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig"
	microsoft_mdm "github.com/fleetdm/fleet/v4/server/mdm/microsoft"
	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
	"github.com/google/go-cmp/cmp"
	"github.com/jmoiron/sqlx"
)

func (ds *Datastore) GetMDMCommandPlatform(ctx context.Context, commandUUID string) (string, error) {
	stmt := `
SELECT CASE
	WHEN EXISTS (SELECT 1 FROM nano_commands WHERE command_uuid = ?) THEN 'darwin'
	WHEN EXISTS (SELECT 1 FROM windows_mdm_commands WHERE command_uuid = ?) THEN 'windows'
	WHEN EXISTS (SELECT 1 FROM host_vpp_software_installs WHERE command_uuid = ? AND platform = 'android') THEN 'android'
	ELSE ''
END AS platform
`

	var p string
	if err := sqlx.GetContext(ctx, ds.reader(ctx), &p, stmt, commandUUID, commandUUID, commandUUID); err != nil {
		return "", err
	}
	if p == "" {
		return "", ctxerr.Wrap(ctx, notFound("MDMCommand").WithName(commandUUID))
	}

	return p, nil
}

func getCombinedMDMCommandsQuery(ds *Datastore, hostFilter string) (string, []interface{}) {
	appleStmt := `
SELECT
    nvq.id as host_uuid,
    nvq.command_uuid,
    COALESCE(NULLIF(nvq.status, ''), 'Pending') as status,
    COALESCE(nvq.result_updated_at, nvq.created_at) as updated_at,
    nvq.request_type as request_type,
    h.hostname,
    h.team_id
FROM
    nano_view_queue nvq
INNER JOIN
    hosts h
ON
    nvq.id = h.uuid
WHERE
   nvq.active = 1
`

	windowsStmt := `
SELECT
    mwe.host_uuid,
    wmc.command_uuid,
    COALESCE(NULLIF(wmcr.status_code, ''), '101') as status,
    COALESCE(wmc.updated_at, wmc.created_at) as updated_at,
    wmc.target_loc_uri as request_type,
    h.hostname,
    h.team_id
FROM windows_mdm_commands wmc
LEFT JOIN windows_mdm_command_queue wmcq ON wmcq.command_uuid = wmc.command_uuid
LEFT JOIN windows_mdm_command_results wmcr ON wmc.command_uuid = wmcr.command_uuid
INNER JOIN mdm_windows_enrollments mwe ON wmcq.enrollment_id = mwe.id OR wmcr.enrollment_id = mwe.id
INNER JOIN hosts h ON h.uuid = mwe.host_uuid
WHERE TRUE
`

	var params []interface{}
	appleStmtWithFilter, params := ds.whereFilterHostsByIdentifier(hostFilter, appleStmt, params)
	windowsStmtWithFilter, params := ds.whereFilterHostsByIdentifier(hostFilter, windowsStmt, params)

	stmt := fmt.Sprintf(
		`SELECT * FROM ((%s) UNION ALL (%s)) as combined_commands WHERE `,
		appleStmtWithFilter, windowsStmtWithFilter,
	)

	return stmt, params
}

func (ds *Datastore) ListMDMCommands(
	ctx context.Context,
	tmFilter fleet.TeamFilter,
	listOpts *fleet.MDMCommandListOptions,
) ([]*fleet.MDMCommand, error) {
	if listOpts != nil && listOpts.Filters.HostIdentifier != "" {
		// separate codepath for more performant query by host identifier
		return ds.listMDMCommandsByHostIdentifier(ctx, tmFilter, listOpts)
	}

	jointStmt, params := getCombinedMDMCommandsQuery(ds, listOpts.Filters.HostIdentifier)
	jointStmt += ds.whereFilterHostsByTeams(tmFilter, "combined_commands")
	jointStmt, params = addRequestTypeFilter(jointStmt, &listOpts.Filters, params)
	jointStmt, params = appendListOptionsWithCursorToSQL(jointStmt, params, &listOpts.ListOptions)
	var results []*fleet.MDMCommand
	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &results, jointStmt, params...); err != nil {
		return nil, ctxerr.Wrap(ctx, err, "list commands")
	}
	return results, nil
}

// listMDMCommandsByHostIdentifier retrieves MDM commands by host identifier. It is implemented as a
// distinct code path to optimize the query for use cases where a client may be polling for the
// status of commands for a specific host.
//
// TODO: Additional optimizations not implemented yet:
//   - restrict ordering by date to a new sorted index (probably `nano_enrollment_queue (id,
//     created_at DESC)` would be a good candidate)
//   - only search by hostname as a fallback if no results are found for UUID or hardware serial
func (ds *Datastore) listMDMCommandsByHostIdentifier(
	ctx context.Context,
	teamFilter fleet.TeamFilter,
	listOpts *fleet.MDMCommandListOptions,
) ([]*fleet.MDMCommand, error) {
	if listOpts == nil || listOpts.Filters.HostIdentifier == "" {
		return nil, ctxerr.Wrap(ctx, errors.New("listMDMCommandsByHostIdentifier requires non-empty listOpts.Filters.HostIdentifier"))
	}

	// First, search for host by identifier (hostname, uuid, or hardware_serial).
	//
	// NOTE: We're not using existing methods like ds.whereFilterHostsByIdentifier,
	// ds.HostIDsByIdentifier, ds.HostLiteByIdentifier because those methods are poorly
	// optimized for the indexes we currently have on the hosts table.
	// They filter with disjunctive conditions like `hostname = ? OR uuid = ?` as well as
	// `? IN(hostname, uuid)`. These existing queries aren't really suited for either composite
	// indexes or indexes on individual columns, and the optimizer ends up with executions that
	// resort full table scans or minimally filtered results (when the optimizer is using
	// indexes on team id and the like. Full-text indexes might be an option, but we've had
	// difficulties managing those for the hosts table in the past.
	//
	// So we're writing a custom query here that uses a UNION with three subqueries, each targeting
	// a specific column index: hostname, uuid, and hardware_serial.

	identifier := listOpts.Filters.HostIdentifier
	whereTeam := ds.whereFilterHostsByTeams(teamFilter, "h")
	columns := "id, uuid, hardware_serial, hostname, platform, team_id"

	// TODO: Add index for `hostname` or remove query? If removing, we'd need to update API
	// documentation? Breaking change? For now, adding a secondary team filter inside hostname part
	// of the union subquery to narrow the scope somewhat
	stmt := `
SELECT ` + columns + ` FROM (
	SELECT ` + columns + ` FROM hosts h WHERE hostname = ? AND ` + whereTeam + `
	UNION SELECT ` + columns + ` FROM hosts WHERE uuid = ?
	UNION SELECT ` + columns + ` FROM hosts WHERE hardware_serial = ? ) h
WHERE ` + whereTeam

	var dest []fleet.Host // NOTE: we're using the hosts struct for convenience, but it will not be fully populated
	args := []any{identifier, identifier, identifier}
	err := sqlx.SelectContext(ctx, ds.reader(ctx), &dest, stmt, args...)
	switch {
	case err != nil:
		return nil, ctxerr.Wrap(ctx, err, "get host by identifier for mdm")
	case len(dest) == 0:
		// TODO: should we return an empty slice or an error?
		return []*fleet.MDMCommand{}, nil
	case len(dest) > 1:
		// TODO: how should we handle this unexpected case?
		level.Debug(ds.logger).Log("msg", "list mdm commands: multiple hosts found for identifier",
			"identifier", identifier, "count", len(dest),
		)
	}

	// Next, build the query to list MDM commands. If the found host(s) are on the same platform,
	// we can optimize the query by skipping the UNION ALL and using a single query targeted to the
	// platform.

	var appleStmt, winStmt string
	var appleParams, winParams []any
	var appleUUIDs, winUUIDs []string
	byUUID := make(map[string]fleet.Host, len(dest)) // map UUID to host so that we can loop over command results to add hostname and team info and avoid joining hosts to commands in DB
	for _, h := range dest {
		if prev, ok := byUUID[h.UUID]; ok {
			// TODO: how should we handle this unexpected case?
			level.Debug(ds.logger).Log("msg", "list mdm commands: multiple hosts found for identifier",
				"keeping", fmt.Sprintf("id: %d uuid: %s serial: %s hostname: %s platform: %s team: %+v", h.ID, h.UUID, h.HardwareSerial, h.Hostname, h.Platform, h.TeamID),
				"skipping", fmt.Sprintf("id: %d uuid: %s serial: %s hostname: %s platform: %s team: %+v", prev.ID, prev.UUID, prev.HardwareSerial, prev.Hostname, prev.Platform, prev.TeamID),
			)
		}
		byUUID[h.UUID] = h
		switch fleet.MDMPlatform(h.Platform) {
		case "darwin":
			appleUUIDs = append(appleUUIDs, h.UUID)
		case "windows":
			winUUIDs = append(winUUIDs, h.UUID)
		}
	}

	if len(appleUUIDs) > 0 {
		appleParams = []any{appleUUIDs}
		appleStmt = `
SELECT
	nq.id AS host_uuid,
	nc.command_uuid,
	COALESCE(ncr.updated_at, nc.created_at) AS updated_at,
	COALESCE(NULLIF(ncr.status, ''), 'Pending') AS status,
	request_type
FROM
	nano_enrollment_queue nq
	JOIN nano_commands nc ON nq.command_uuid = nc.command_uuid
	LEFT JOIN nano_command_results ncr ON nq.id = ncr.id
		AND nc.command_uuid = ncr.command_uuid
WHERE
	nq.id IN(?) AND nq.active = 1`

		appleStmt, appleParams = addRequestTypeFilter(appleStmt, &listOpts.Filters, appleParams)
		appleStmt, appleParams, err = sqlx.In(appleStmt, appleParams...)
		if err != nil {
			return nil, ctxerr.Wrap(ctx, err, "prepare query to list MDM commands for Apple devices")
		}
	}

	if len(winUUIDs) > 0 {
		winParams = []any{winUUIDs}
		winStmt = `
SELECT
	mwe.host_uuid,
	wq.command_uuid,
	COALESCE(wcr.updated_at, wc.created_at) AS updated_at,
	COALESCE(NULLIF(wcr.status_code, ''), '101') AS status,
	wc.target_loc_uri AS request_type
FROM
	windows_mdm_command_queue wq
	JOIN mdm_windows_enrollments mwe ON mwe.id = wq.enrollment_id
	JOIN windows_mdm_commands wc ON wc.command_uuid = wq.command_uuid
	LEFT JOIN windows_mdm_command_results wcr ON wcr.command_uuid = wq.command_uuid
		AND wcr.enrollment_id = wq.enrollment_id
WHERE
	mwe.host_uuid IN (?)`

		winStmt, winParams = addRequestTypeFilter(winStmt, &listOpts.Filters, winParams)
		winStmt, winParams, err = sqlx.In(winStmt, winParams...)
		if err != nil {
			return nil, ctxerr.Wrap(ctx, err, "prepare query to list MDM commands for Windows devices")
		}
	}

	var listStmt string
	var params []any
	switch {
	case len(appleUUIDs) > 0 && len(winUUIDs) > 0:
		listStmt = fmt.Sprintf(`SELECT * FROM ((%s) UNION ALL (%s)) u`,
			appleStmt, winStmt)
		params = append(params, appleParams...)
		params = append(params, winParams...)
	case len(appleUUIDs) > 0:
		listStmt = appleStmt
		params = appleParams
	case len(winUUIDs) > 0:
		listStmt = winStmt
		params = winParams
	}

	// TODO: Maybe move this to the service method? What about pagination metadata?
	if listOpts.OrderKey == "" {
		listOpts.OrderKey = "updated_at"
	}
	// // FIXME: We probably ought to modify how listOptionsFromRequest in transport.go applies the
	// // default order direction. Defaulting to ascending doesn't make sense for date fields like
	// // updated_at. List options are decoded by transport before the specific gets the request
	// // struct so there's no way apply a different default because at that point we can't tell if
	// // the direction was set by the user or not. One approach would be to have listOptionsFromRequest
	// // check if the order key is a date field (i.e. it ends with "_at") and default to descending
	// // in those cases.
	// if listOpts.OrderDirection == "" {
	// 	listOpts.OrderDirection = fleet.OrderDescending
	// }
	if listOpts.PerPage == 0 {
		listOpts.PerPage = 10
	}
	listStmt, params = appendListOptionsWithCursorToSQL(listStmt, params, &listOpts.ListOptions)

	var results []*fleet.MDMCommand
	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &results, listStmt, params...); err != nil {
		return nil, ctxerr.Wrap(ctx, err, "list commands")
	}

	// Add hostname and team info to the results based on the host UUIDs.
	for i := range results {
		if host, ok := byUUID[results[i].HostUUID]; ok {
			results[i].Hostname = host.Hostname
			results[i].TeamID = host.TeamID
		}
	}

	return results, nil
}

func addRequestTypeFilter(stmt string, filter *fleet.MDMCommandFilters, params []interface{}) (string, []interface{}) {
	if filter.RequestType != "" {
		stmt += " AND request_type = ?"
		params = append(params, filter.RequestType)
	}

	return stmt, params
}

func (ds *Datastore) getMDMCommand(ctx context.Context, q sqlx.QueryerContext, cmdUUID string) (*fleet.MDMCommand, error) {
	stmt, _ := getCombinedMDMCommandsQuery(ds, "")
	stmt += "command_uuid = ?"

	var cmd fleet.MDMCommand
	if err := sqlx.GetContext(ctx, q, &cmd, stmt, cmdUUID); err != nil {
		return nil, ctxerr.Wrap(ctx, err, "get mdm command by UUID")
	}
	return &cmd, nil
}

func (ds *Datastore) BatchSetMDMProfiles(ctx context.Context, tmID *uint, macProfiles []*fleet.MDMAppleConfigProfile,
	winProfiles []*fleet.MDMWindowsConfigProfile, macDeclarations []*fleet.MDMAppleDeclaration, androidProfiles []*fleet.MDMAndroidConfigProfile, profilesVariablesByIdentifier []fleet.MDMProfileIdentifierFleetVariables,
) (updates fleet.MDMProfilesUpdates, err error) {
	err = ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
		var err error
		// Pass profilesVariablesByIdentifier to Windows profiles to save variable associations
		if updates.WindowsConfigProfile, err = ds.batchSetMDMWindowsProfilesDB(ctx, tx, tmID, winProfiles, profilesVariablesByIdentifier); err != nil {
			return ctxerr.Wrap(ctx, err, "batch set windows profiles")
		}

		// Apple profiles also support Fleet variables
		if updates.AppleConfigProfile, err = ds.batchSetMDMAppleProfilesDB(ctx, tx, tmID, macProfiles, profilesVariablesByIdentifier); err != nil {
			return ctxerr.Wrap(ctx, err, "batch set apple profiles")
		}

		if updates.AppleDeclaration, err = ds.batchSetMDMAppleDeclarations(ctx, tx, tmID, macDeclarations); err != nil {
			return ctxerr.Wrap(ctx, err, "batch set apple declarations")
		}

		if updates.AndroidConfigProfile, err = ds.batchSetMDMAndroidProfiles(ctx, tx, tmID, androidProfiles); err != nil {
			return ctxerr.Wrap(ctx, err, "batch set android profiles")
		}

		return nil
	})
	return updates, err
}

func (ds *Datastore) ListMDMConfigProfiles(ctx context.Context, teamID *uint, opt fleet.ListOptions) ([]*fleet.MDMConfigProfilePayload, *fleet.PaginationMetadata, error) {
	// this lists custom profiles, it explicitly filters out the fleet-reserved
	// ones (reserved identifiers for Apple profiles, reserved names for Windows).

	var profs []*fleet.MDMConfigProfilePayload

	const selectStmt = `
SELECT
	profile_uuid,
	team_id,
	name,
	scope,
	platform,
	identifier,
	checksum,
	created_at,
	uploaded_at
FROM (
	SELECT
		profile_uuid,
		team_id,
		name,
		scope,
		'darwin' as platform,
		identifier,
		checksum,
		created_at,
		uploaded_at
	FROM
		mdm_apple_configuration_profiles
	WHERE
		team_id = ? AND
		identifier NOT IN (?)

	UNION ALL

	SELECT
		profile_uuid,
		team_id,
		name,
		'' as scope,
		'windows' as platform,
		'' as identifier,
		'' as checksum,
		created_at,
		uploaded_at
	FROM
		mdm_windows_configuration_profiles
	WHERE
		team_id = ? AND
		name NOT IN (?)

	UNION ALL

	SELECT
		declaration_uuid AS profile_uuid,
		team_id,
		name,
		scope,
		'darwin' AS platform,
		identifier,
		token AS checksum,
		created_at,
		uploaded_at
	FROM mdm_apple_declarations
	WHERE team_id = ? AND
		name NOT IN (?)

		UNION ALL

	SELECT
		profile_uuid,
		team_id,
		name,
		'' AS scope,
		'android' AS platform,
		'' AS identifier,
		'' AS checksum,
		created_at,
		uploaded_at
	FROM mdm_android_configuration_profiles
	WHERE team_id = ? AND
		name NOT IN (?)
) as combined_profiles
`

	var globalOrTeamID uint
	if teamID != nil {
		globalOrTeamID = *teamID
	}

	fleetIdentsMap := mobileconfig.FleetPayloadIdentifiers()
	fleetIdentifiers := make([]string, 0, len(fleetIdentsMap))
	for k := range fleetIdentsMap {
		fleetIdentifiers = append(fleetIdentifiers, k)
	}
	fleetNamesMap := mdm.FleetReservedProfileNames()
	fleetNames := make([]string, 0, len(fleetNamesMap))
	for k := range fleetNamesMap {
		fleetNames = append(fleetNames, k)
	}

	args := []any{globalOrTeamID, fleetIdentifiers, globalOrTeamID, fleetNames, globalOrTeamID, fleetNames, globalOrTeamID, fleetNames}
	stmt, args := appendListOptionsWithCursorToSQL(selectStmt, args, &opt)

	stmt, args, err := sqlx.In(stmt, args...)
	if err != nil {
		return nil, nil, ctxerr.Wrap(ctx, err, "sqlx.In ListMDMConfigProfiles")
	}

	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &profs, stmt, args...); err != nil {
		return nil, nil, ctxerr.Wrap(ctx, err, "select profiles")
	}

	var metaData *fleet.PaginationMetadata
	if opt.IncludeMetadata {
		metaData = &fleet.PaginationMetadata{HasPreviousResults: opt.Page > 0}
		if len(profs) > int(opt.PerPage) { //nolint:gosec // dismiss G115
			metaData.HasNextResults = true
			profs = profs[:len(profs)-1]
		}
	}

	// load the labels associated with those profiles
	var winProfUUIDs, macProfUUIDs, androidProfUUIDs, macDeclUUIDs []string
	for _, prof := range profs {
		switch prof.Platform {
		case "windows":
			winProfUUIDs = append(winProfUUIDs, prof.ProfileUUID)
		case "android":
			androidProfUUIDs = append(androidProfUUIDs, prof.ProfileUUID)
		default:
			if strings.HasPrefix(prof.ProfileUUID, fleet.MDMAppleDeclarationUUIDPrefix) {
				macDeclUUIDs = append(macDeclUUIDs, prof.ProfileUUID)
				continue
			}

			macProfUUIDs = append(macProfUUIDs, prof.ProfileUUID)
		}
	}
	labels, err := ds.listProfileLabelsForProfiles(ctx, winProfUUIDs, macProfUUIDs, androidProfUUIDs, macDeclUUIDs)
	if err != nil {
		return nil, nil, err
	}

	// match the labels with their profiles
	profMap := make(map[string]*fleet.MDMConfigProfilePayload, len(profs))
	for _, prof := range profs {
		profMap[prof.ProfileUUID] = prof
	}
	for _, label := range labels {
		if prof, ok := profMap[label.ProfileUUID]; ok {
			switch {
			case label.Exclude && label.RequireAll:
				// this should never happen so log it for debugging
				level.Debug(ds.logger).Log("msg", "unsupported profile label: cannot be both exclude and require all",
					"profile_uuid", label.ProfileUUID,
					"label_name", label.LabelName,
				)
			case label.Exclude && !label.RequireAll:
				prof.LabelsExcludeAny = append(prof.LabelsExcludeAny, label)
			case !label.Exclude && !label.RequireAll:
				prof.LabelsIncludeAny = append(prof.LabelsIncludeAny, label)
			default:
				// default include all
				prof.LabelsIncludeAll = append(prof.LabelsIncludeAll, label)
			}
		}
	}

	return profs, metaData, nil
}

func (ds *Datastore) listProfileLabelsForProfiles(ctx context.Context, winProfUUIDs, macProfUUIDs, androidProfUUIDs, macDeclUUIDs []string) ([]fleet.ConfigurationProfileLabel, error) {
	// load the labels associated with those profiles
	const labelsStmt = `
SELECT
	COALESCE(apple_profile_uuid, windows_profile_uuid, android_profile_uuid) as profile_uuid,
	label_name,
	COALESCE(label_id, 0) as label_id,
	IF(label_id IS NULL, 1, 0) as broken,
	exclude,
	require_all
FROM
	mdm_configuration_profile_labels mcpl
WHERE
	mcpl.apple_profile_uuid IN (?) OR
	mcpl.windows_profile_uuid IN (?) OR
	mcpl.android_profile_uuid IN (?)
UNION ALL
SELECT
	apple_declaration_uuid as profile_uuid,
	label_name,
	COALESCE(label_id, 0) as label_id,
	IF(label_id IS NULL, 1, 0) as broken,
	exclude,
	require_all
FROM
	mdm_declaration_labels mdl
WHERE
	mdl.apple_declaration_uuid IN (?)
ORDER BY
	profile_uuid, label_name
`
	// ensure there's at least one (non-matching) value in the slice so the IN
	// clause is valid
	if len(winProfUUIDs) == 0 {
		winProfUUIDs = []string{"-"}
	}
	if len(macProfUUIDs) == 0 {
		macProfUUIDs = []string{"-"}
	}
	if len(androidProfUUIDs) == 0 {
		androidProfUUIDs = []string{"-"}
	}
	if len(macDeclUUIDs) == 0 {
		macDeclUUIDs = []string{"-"}
	}

	stmt, args, err := sqlx.In(labelsStmt, macProfUUIDs, winProfUUIDs, androidProfUUIDs, macDeclUUIDs)
	if err != nil {
		return nil, ctxerr.Wrap(ctx, err, "sqlx.In to list labels for profiles")
	}

	var labels []fleet.ConfigurationProfileLabel
	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &labels, stmt, args...); err != nil {
		return nil, ctxerr.Wrap(ctx, err, "select profiles labels")
	}
	return labels, nil
}

func (ds *Datastore) BulkSetPendingMDMHostProfiles(
	ctx context.Context,
	hostIDs, teamIDs []uint,
	profileUUIDs, hostUUIDs []string,
) (updates fleet.MDMProfilesUpdates, err error) {
	err = ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
		updates, err = ds.bulkSetPendingMDMHostProfilesDB(ctx, tx, hostIDs, teamIDs, profileUUIDs, hostUUIDs)
		return err
	})
	return updates, err
}

// Note that team ID 0 is used for profiles that apply to hosts in no team
// (i.e. pass 0 in that case as part of the teamIDs slice). Only one of the
// slice arguments can have values.
func (ds *Datastore) bulkSetPendingMDMHostProfilesDB(
	ctx context.Context,
	tx sqlx.ExtContext,
	hostIDs, teamIDs []uint,
	profileUUIDs, hostUUIDs []string,
) (updates fleet.MDMProfilesUpdates, err error) {
	var (
		countArgs        int
		macProfUUIDs     []string
		winProfUUIDs     []string
		androidProfUUIDs []string
		hasAppleDecls    bool
	)

	if len(hostIDs) > 0 {
		countArgs++
	}
	if len(teamIDs) > 0 {
		countArgs++
	}
	if len(profileUUIDs) > 0 {
		countArgs++

		// split into mac, win and android profiles
		for _, puid := range profileUUIDs {
			if strings.HasPrefix(puid, fleet.MDMAppleProfileUUIDPrefix) { //nolint:gocritic // ignore ifElseChain
				macProfUUIDs = append(macProfUUIDs, puid)
			} else if strings.HasPrefix(puid, fleet.MDMAppleDeclarationUUIDPrefix) {
				hasAppleDecls = true
			} else if strings.HasPrefix(puid, fleet.MDMAndroidProfileUUIDPrefix) {
				androidProfUUIDs = append(androidProfUUIDs, puid)
			} else {
				// Note: defaulting to windows profiles without checking the prefix as
				// many tests fail otherwise and it's a whole rabbit hole that I can't
				// address at the moment.
				winProfUUIDs = append(winProfUUIDs, puid)
			}
		}
	}
	if len(hostUUIDs) > 0 {
		countArgs++
	}
	if countArgs > 1 {
		return updates, errors.New("only one of hostIDs, teamIDs, profileUUIDs or hostUUIDs can be provided")
	}
	if countArgs == 0 {
		return updates, nil
	}

	var countProfUUIDs int
	if len(macProfUUIDs) > 0 {
		countProfUUIDs++
	}
	if len(winProfUUIDs) > 0 {
		countProfUUIDs++
	}
	if len(androidProfUUIDs) > 0 {
		countProfUUIDs++
	}
	if hasAppleDecls {
		countProfUUIDs++
	}
	if countProfUUIDs > 1 {
		return updates, errors.New("profile uuids must be all Apple profiles, all Apple declarations, all Windows profiles, or all Android profiles")
	}

	var (
		hosts    []fleet.Host
		args     []any
		uuidStmt string
	)

	switch {
	case len(hostUUIDs) > 0:
		// TODO: if a very large number (~65K) of uuids was provided, could
		// result in too many placeholders (not an immediate concern).
		uuidStmt = `SELECT uuid, platform FROM hosts WHERE uuid IN (?)`
		args = append(args, hostUUIDs)

	case len(hostIDs) > 0:
		// TODO: if a very large number (~65K) of uuids was provided, could
		// result in too many placeholders (not an immediate concern).
		uuidStmt = `SELECT uuid, platform FROM hosts WHERE id IN (?)`
		args = append(args, hostIDs)

	case len(teamIDs) > 0:
		// TODO: if a very large number (~65K) of team IDs was provided, could
		// result in too many placeholders (not an immediate concern).
		uuidStmt = `SELECT uuid, platform FROM hosts WHERE `
		if len(teamIDs) == 1 && teamIDs[0] == 0 {
			uuidStmt += `team_id IS NULL`
		} else {
			uuidStmt += `team_id IN (?)`
			args = append(args, teamIDs)
			for _, tmID := range teamIDs {
				if tmID == 0 {
					uuidStmt += ` OR team_id IS NULL`
					break
				}
			}
		}

	case len(macProfUUIDs) > 0:
		// TODO: if a very large number (~65K/2) of profile UUIDs was provided, could
		// result in too many placeholders (not an immediate concern).
		uuidStmt = `
SELECT DISTINCT h.uuid, h.platform
FROM hosts h
JOIN mdm_apple_configuration_profiles macp
	ON h.team_id = macp.team_id OR (h.team_id IS NULL AND macp.team_id = 0)
LEFT JOIN host_mdm_apple_profiles hmap
	ON h.uuid = hmap.host_uuid
WHERE
	macp.profile_uuid IN (?) AND (h.platform = 'darwin' OR h.platform = 'ios' OR h.platform = 'ipados')
OR
	hmap.profile_uuid IN (?) AND (h.platform = 'darwin' OR h.platform = 'ios' OR h.platform = 'ipados')`
		args = append(args, macProfUUIDs, macProfUUIDs)

	case len(winProfUUIDs) > 0:
		// TODO: if a very large number (~65K/2) of profile IDs was provided, could
		// result in too many placeholders (not an immediate concern).
		uuidStmt = `
SELECT DISTINCT h.uuid, h.platform
FROM hosts h
JOIN mdm_windows_configuration_profiles mawp
	ON h.team_id = mawp.team_id OR (h.team_id IS NULL AND mawp.team_id = 0)
LEFT JOIN host_mdm_windows_profiles hmwp
	ON h.uuid = hmwp.host_uuid
WHERE
	mawp.profile_uuid IN (?) AND h.platform = 'windows'
OR
	hmwp.profile_uuid IN (?) AND h.platform = 'windows'`
		args = append(args, winProfUUIDs, winProfUUIDs)

	case len(androidProfUUIDs) > 0:
		// TODO: if a very large number (~65K/2) of profile IDs was provided, could
		// result in too many placeholders (not an immediate concern).
		uuidStmt = `
SELECT DISTINCT h.uuid, h.platform
FROM hosts h
JOIN mdm_android_configuration_profiles maap
	ON h.team_id = maap.team_id OR (h.team_id IS NULL AND maap.team_id = 0)
LEFT JOIN host_mdm_android_profiles hmap
	ON h.uuid = hmap.host_uuid
WHERE
	maap.profile_uuid IN (?) AND h.platform = 'android'
OR
	hmap.profile_uuid IN (?) AND h.platform = 'android'`
		args = append(args, androidProfUUIDs, androidProfUUIDs)
	}

	// TODO: this could be optimized to avoid querying for platform when
	// profileIDs or profileUUIDs are provided.
	if len(hosts) == 0 && !hasAppleDecls {
		uuidStmt, args, err := sqlx.In(uuidStmt, args...)
		if err != nil {
			return updates, ctxerr.Wrap(ctx, err, "prepare query to load host UUIDs")
		}
		if err := sqlx.SelectContext(ctx, tx, &hosts, uuidStmt, args...); err != nil {
			return updates, ctxerr.Wrap(ctx, err, "execute query to load host UUIDs")
		}
	}

	var appleHosts []string
	var winHosts []string
	var androidHosts []string
	for _, h := range hosts {
		switch h.Platform {
		case "darwin", "ios", "ipados":
			appleHosts = append(appleHosts, h.UUID)
		case "windows":
			winHosts = append(winHosts, h.UUID)
		case "android":
			androidHosts = append(androidHosts, h.UUID)
		default:
			level.Debug(ds.logger).Log(
				"msg", "tried to set profile status for a host with unsupported platform",
				"platform", h.Platform,
				"host_uuid", h.UUID,
			)
		}
	}

	updates.AppleConfigProfile, err = ds.bulkSetPendingMDMAppleHostProfilesDB(ctx, tx, appleHosts, profileUUIDs)
	if err != nil {
		return updates, ctxerr.Wrap(ctx, err, "bulk set pending apple host profiles")
	}

	updates.WindowsConfigProfile, err = ds.bulkSetPendingMDMWindowsHostProfilesDB(ctx, tx, winHosts, profileUUIDs)
	if err != nil {
		return updates, ctxerr.Wrap(ctx, err, "bulk set pending windows host profiles")
	}

	updates.AndroidConfigProfile, err = ds.bulkSetPendingMDMAndroidHostProfilesDB(ctx, androidHosts)
	if err != nil {
		return updates, ctxerr.Wrap(ctx, err, "bulk set pending android host profiles")
	}

	const defaultBatchSize = 1000
	batchSize := defaultBatchSize
	if ds.testUpsertMDMDesiredProfilesBatchSize > 0 {
		batchSize = ds.testUpsertMDMDesiredProfilesBatchSize
	}
	// TODO(roberto): this method currently sets the state of all
	// declarations for all hosts. I don't see an immediate concern
	// (and my hunch is that we could even do the same for
	// profiles) but this could be optimized to use only a provided
	// set of host uuids.
	//
	// Note(victor): Why is the status being set to nil? Shouldn't it be set to pending?
	// Or at least pending for install and nil for remove profiles. Please update this comment if you know.
	// This method is called bulkSetPendingMDMHostProfilesDB, so it is confusing that the status is NOT explicitly set to pending.
	_, updates.AppleDeclaration, err = mdmAppleBatchSetHostDeclarationStateDB(ctx, tx, batchSize, nil)
	if err != nil {
		return updates, ctxerr.Wrap(ctx, err, "bulk set pending apple declarations")
	}

	return updates, nil
}

func (ds *Datastore) UpdateHostMDMProfilesVerification(ctx context.Context, host *fleet.Host, toVerify, toFail, toRetry []string) error {
	return ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
		if err := setMDMProfilesVerifiedDB(ctx, tx, host, toVerify); err != nil {
			return err
		}
		if err := setMDMProfilesFailedDB(ctx, tx, host, toFail); err != nil {
			return err
		}
		if err := setMDMProfilesRetryDB(ctx, tx, host, toRetry); err != nil {
			return err
		}
		return nil
	})
}

// setMDMProfilesRetryDB sets the status of the given identifiers to retry (nil) and increments the retry count
func setMDMProfilesRetryDB(ctx context.Context, tx sqlx.ExtContext, host *fleet.Host, identifiersOrNames []string) error {
	if len(identifiersOrNames) == 0 {
		return nil
	}

	const baseStmt = `
UPDATE
	%s
SET
	status = NULL,
	detail = '',
	retries = retries + 1
WHERE
	host_uuid = ?
	AND operation_type = ?
	-- do not increment retry unnecessarily if the status is already null, no MDM command was sent
	AND status IS NOT NULL
	AND %s IN(?)`

	args := []interface{}{
		host.UUID,
		fleet.MDMOperationTypeInstall,
		identifiersOrNames,
	}

	var stmt string
	switch host.Platform {
	case "darwin", "ios", "ipados":
		stmt = fmt.Sprintf(baseStmt, "host_mdm_apple_profiles", "profile_identifier")
	case "windows":
		stmt = fmt.Sprintf(baseStmt, "host_mdm_windows_profiles", "profile_name")
	default:
		return fmt.Errorf("unsupported platform %s", host.Platform)
	}
	stmt, args, err := sqlx.In(stmt, args...)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "building sql statement to set retry host profiles")
	}

	if _, err := tx.ExecContext(ctx, stmt, args...); err != nil {
		return ctxerr.Wrap(ctx, err, "setting retry host profiles")
	}
	return nil
}

// setMDMProfilesFailedDB sets the status of the given identifiers to failed if the current status
// is verifying or verified. It also sets the detail to a message indicating that the profile was
// either verifying or verified. Only profiles with the install operation type are updated.
func setMDMProfilesFailedDB(ctx context.Context, tx sqlx.ExtContext, host *fleet.Host, identifiersOrNames []string) error {
	if len(identifiersOrNames) == 0 {
		return nil
	}

	const baseStmt = `
UPDATE
	%s
SET
	detail = if(status = ?, ?, ?),
	status = ?
WHERE
	host_uuid = ?
	AND status IN(?)
	AND operation_type = ?
	AND %s IN(?)`

	var stmt string
	switch host.Platform {
	case "darwin", "ios", "ipados":
		stmt = fmt.Sprintf(baseStmt, "host_mdm_apple_profiles", "profile_identifier")
	case "windows":
		stmt = fmt.Sprintf(baseStmt, "host_mdm_windows_profiles", "profile_name")
	default:
		return fmt.Errorf("unsupported platform %s", host.Platform)
	}

	args := []interface{}{
		fleet.MDMDeliveryVerifying,
		fleet.HostMDMProfileDetailFailedWasVerifying,
		fleet.HostMDMProfileDetailFailedWasVerified,
		fleet.MDMDeliveryFailed,
		host.UUID,
		[]interface{}{
			fleet.MDMDeliveryVerifying,
			fleet.MDMDeliveryVerified,
		},
		fleet.MDMOperationTypeInstall,
		identifiersOrNames,
	}
	stmt, args, err := sqlx.In(stmt, args...)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "building sql statement to set failed host profiles")
	}

	if _, err := tx.ExecContext(ctx, stmt, args...); err != nil {
		return ctxerr.Wrap(ctx, err, "setting failed host profiles")
	}
	return nil
}

// setMDMProfilesVerifiedDB sets the status of the given identifiers to verified if the current
// status is verifying. Only profiles with the install operation type are updated.
func setMDMProfilesVerifiedDB(ctx context.Context, tx sqlx.ExtContext, host *fleet.Host, identifiersOrNames []string) error {
	if len(identifiersOrNames) == 0 {
		return nil
	}

	const baseStmt = `
UPDATE
	%s
SET
	detail = '',
	status = ?
WHERE
	host_uuid = ?
	AND status IN(?)
	AND operation_type = ?
	AND %s IN(?)`

	var stmt string
	switch host.Platform {
	case "darwin", "ios", "ipados":
		stmt = fmt.Sprintf(baseStmt, "host_mdm_apple_profiles", "profile_identifier")
	case "windows":
		stmt = fmt.Sprintf(baseStmt, "host_mdm_windows_profiles", "profile_name")
	default:
		return fmt.Errorf("unsupported platform %s", host.Platform)
	}

	args := []interface{}{
		fleet.MDMDeliveryVerified,
		host.UUID,
		[]interface{}{
			fleet.MDMDeliveryPending,
			fleet.MDMDeliveryVerifying,
			fleet.MDMDeliveryFailed,
		},
		fleet.MDMOperationTypeInstall,
		identifiersOrNames,
	}
	stmt, args, err := sqlx.In(stmt, args...)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "building sql statement to set verified host macOS profiles")
	}

	if _, err := tx.ExecContext(ctx, stmt, args...); err != nil {
		return ctxerr.Wrap(ctx, err, "setting verified host profiles")
	}
	return nil
}

func (ds *Datastore) GetHostMDMProfilesExpectedForVerification(ctx context.Context, host *fleet.Host) (map[string]*fleet.ExpectedMDMProfile, error) {
	var teamID uint
	if host.TeamID != nil {
		teamID = *host.TeamID
	}

	switch host.Platform {
	case "darwin", "ios", "ipados":
		return ds.getHostMDMAppleProfilesExpectedForVerification(ctx, teamID, host)
	case "windows":
		return ds.getHostMDMWindowsProfilesExpectedForVerification(ctx, teamID, host.ID)
	default:
		return nil, fmt.Errorf("unsupported platform: %s", host.Platform)
	}
}

func (ds *Datastore) getHostMDMWindowsProfilesExpectedForVerification(ctx context.Context, teamID, hostID uint) (map[string]*fleet.ExpectedMDMProfile, error) {
	stmt := `
-- profiles without labels
SELECT
    mwcp.profile_uuid AS profile_uuid,
	name,
	syncml AS raw_profile,
	min(mwcp.uploaded_at) AS earliest_install_date,
	0 AS count_profile_labels,
	0 AS count_non_broken_labels,
	0 AS count_host_labels
FROM
	mdm_windows_configuration_profiles mwcp
WHERE
	mwcp.team_id = ? AND
	NOT EXISTS (
		SELECT
			1
		FROM
			mdm_configuration_profile_labels mcpl
		WHERE
			mcpl.windows_profile_uuid = mwcp.profile_uuid
	)
GROUP BY profile_uuid, name, syncml

UNION

-- label-based profiles where the host is a member of all the labels (include-all).
-- by design, "include" labels cannot match if they are broken (the host cannot be
-- a member of a deleted label).
SELECT
	mwcp.profile_uuid AS profile_uuid,
	name,
	syncml AS raw_profile,
	min(mwcp.uploaded_at) AS earliest_install_date,
	COUNT(*) AS count_profile_labels,
	COUNT(mcpl.label_id) as count_non_broken_labels,
	COUNT(lm.label_id) AS count_host_labels
FROM
	mdm_windows_configuration_profiles mwcp
	JOIN mdm_configuration_profile_labels mcpl
		ON mcpl.windows_profile_uuid = mwcp.profile_uuid AND mcpl.exclude = 0 AND mcpl.require_all = 1
	LEFT OUTER JOIN label_membership lm
		ON lm.label_id = mcpl.label_id AND lm.host_id = ?
WHERE
	mwcp.team_id = ?
GROUP BY
	profile_uuid, name, syncml
HAVING
	count_profile_labels > 0 AND
	count_host_labels = count_profile_labels

UNION

-- label-based entities where the host is NOT a member of any of the labels (exclude-any).
-- explicitly ignore profiles with broken excluded labels so that they are never applied.
SELECT
	mwcp.profile_uuid AS profile_uuid,
	name,
	syncml AS raw_profile,
	min(mwcp.uploaded_at) AS earliest_install_date,
	COUNT(*) AS count_profile_labels,
	COUNT(mcpl.label_id) as count_non_broken_labels,
	COUNT(lm.label_id) AS count_host_labels
FROM
	mdm_windows_configuration_profiles mwcp
	JOIN mdm_configuration_profile_labels mcpl
		ON mcpl.windows_profile_uuid = mwcp.profile_uuid AND mcpl.exclude = 1
	LEFT OUTER JOIN label_membership lm
		ON lm.label_id = mcpl.label_id AND lm.host_id = ?
WHERE
	mwcp.team_id = ?
GROUP BY
	profile_uuid, name, syncml
HAVING
	-- considers only the profiles with labels, without any broken label, and with the host not in any label
	count_profile_labels > 0 AND
	count_profile_labels = count_non_broken_labels AND
	count_host_labels = 0

UNION

-- label-based profiles where the host is a member of at least one of the labels (include-any)
SELECT
	mwcp.profile_uuid AS profile_uuid,
	name,
	syncml AS raw_profile,
	min(mwcp.uploaded_at) AS earliest_install_date,
	COUNT(*) AS count_profile_labels,
	COUNT(mcpl.label_id) as count_non_broken_labels,
	COUNT(lm.label_id) AS count_host_labels
FROM
	mdm_windows_configuration_profiles mwcp
	JOIN mdm_configuration_profile_labels mcpl
		ON mcpl.windows_profile_uuid = mwcp.profile_uuid AND mcpl.exclude = 0 AND mcpl.require_all = 0
	LEFT OUTER JOIN label_membership lm
		ON lm.label_id = mcpl.label_id AND lm.host_id = ?
WHERE
	mwcp.team_id = ?
GROUP BY
	profile_uuid, name, syncml
HAVING
	count_profile_labels > 0 AND
	count_host_labels > 0
`
	var profiles []*fleet.ExpectedMDMProfile
	err := sqlx.SelectContext(ctx, ds.reader(ctx), &profiles, stmt, teamID, hostID, teamID, hostID, teamID, hostID, teamID)
	if err != nil {
		return nil, ctxerr.Wrap(ctx, err, "running query for windows profiles")
	}

	byName := make(map[string]*fleet.ExpectedMDMProfile, len(profiles))
	for _, r := range profiles {
		byName[r.Name] = r
	}

	return byName, nil
}

func (ds *Datastore) getHostMDMAppleProfilesExpectedForVerification(ctx context.Context, teamID uint, host *fleet.Host) (map[string]*fleet.ExpectedMDMProfile, error) {
	// TODO This will need to be updated to support scopes
	stmt := `
-- profiles without labels
SELECT
	macp.profile_uuid AS profile_uuid,
	macp.identifier AS identifier,
	0 AS count_profile_labels,
	0 AS count_non_broken_labels,
	0 AS count_host_labels,
	earliest_install_date
FROM
	mdm_apple_configuration_profiles macp
	JOIN (
		SELECT
			checksum,
			min(uploaded_at) AS earliest_install_date
		FROM
			mdm_apple_configuration_profiles
		GROUP BY checksum
	) cs ON macp.checksum = cs.checksum
WHERE
	macp.team_id = ? AND
	NOT EXISTS (
		SELECT
			1
		FROM
			mdm_configuration_profile_labels mcpl
		WHERE
			mcpl.apple_profile_uuid = macp.profile_uuid
	)

UNION

-- label-based profiles where the host is a member of all the labels (include-all)
-- by design, "include" labels cannot match if they are broken (the host cannot be
-- a member of a deleted label).
SELECT
	macp.profile_uuid AS profile_uuid,
	macp.identifier AS identifier,
	COUNT(*) AS count_profile_labels,
	COUNT(mcpl.label_id) AS count_non_broken_labels,
	COUNT(lm.label_id) AS count_host_labels,
	min(earliest_install_date) AS earliest_install_date
FROM
	mdm_apple_configuration_profiles macp
	JOIN (
		SELECT
			checksum,
			min(uploaded_at) AS earliest_install_date
		FROM
			mdm_apple_configuration_profiles
		GROUP BY checksum
	) cs ON macp.checksum = cs.checksum
	JOIN mdm_configuration_profile_labels mcpl
		ON mcpl.apple_profile_uuid = macp.profile_uuid AND mcpl.exclude = 0 AND mcpl.require_all = 1
	LEFT OUTER JOIN label_membership lm
		ON lm.label_id = mcpl.label_id AND lm.host_id = ?
WHERE
	macp.team_id = ?
GROUP BY
	profile_uuid, identifier
HAVING
	count_profile_labels > 0 AND
	count_host_labels = count_profile_labels

UNION

-- label-based entities where the host is NOT a member of any of the labels (exclude-any).
-- explicitly ignore profiles with broken excluded labels so that they are never applied.
SELECT
	macp.profile_uuid AS profile_uuid,
	macp.identifier AS identifier,
	COUNT(*) AS count_profile_labels,
	COUNT(mcpl.label_id) AS count_non_broken_labels,
	COUNT(lm.label_id) AS count_host_labels,
	min(earliest_install_date) AS earliest_install_date
FROM
	mdm_apple_configuration_profiles macp
	JOIN (
		SELECT
			checksum,
			min(uploaded_at) AS earliest_install_date
		FROM
			mdm_apple_configuration_profiles
		GROUP BY checksum
	) cs ON macp.checksum = cs.checksum
	JOIN mdm_configuration_profile_labels mcpl
		ON mcpl.apple_profile_uuid = macp.profile_uuid AND mcpl.exclude = 1
	LEFT OUTER JOIN label_membership lm
		ON lm.label_id = mcpl.label_id AND lm.host_id = ?
WHERE
	macp.team_id = ?
GROUP BY
	profile_uuid, identifier
HAVING
	-- considers only the profiles with labels, without any broken label, and with the host not in any label
	count_profile_labels > 0 AND
	count_profile_labels = count_non_broken_labels AND
	count_host_labels = 0

UNION

-- label-based profiles where the host is a member of at least one of the labels (include-any)
SELECT
	macp.profile_uuid AS profile_uuid,
	macp.identifier AS identifier,
	COUNT(*) AS count_profile_labels,
	COUNT(mcpl.label_id) AS count_non_broken_labels,
	COUNT(lm.label_id) AS count_host_labels,
	min(earliest_install_date) AS earliest_install_date
FROM
	mdm_apple_configuration_profiles macp
	JOIN (
		SELECT
			checksum,
			min(uploaded_at) AS earliest_install_date
		FROM
			mdm_apple_configuration_profiles
		GROUP BY checksum
	) cs ON macp.checksum = cs.checksum
	JOIN mdm_configuration_profile_labels mcpl
		ON mcpl.apple_profile_uuid = macp.profile_uuid AND mcpl.exclude = 0 AND mcpl.require_all = 0
	LEFT OUTER JOIN label_membership lm
		ON lm.label_id = mcpl.label_id AND lm.host_id = ?
WHERE
	macp.team_id = ?
GROUP BY
	profile_uuid, identifier
HAVING
	count_profile_labels > 0 AND
	count_host_labels > 0
`

	var rows []*fleet.ExpectedMDMProfile
	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &rows, stmt, teamID, host.ID, teamID, host.ID, teamID, host.ID, teamID); err != nil {
		return nil, ctxerr.Wrap(ctx, err, fmt.Sprintf("getting expected profiles for host in team %d", teamID))
	}

	// Fetch variables_updated_at for host profiles that have it set and override
	// earliest_install_date if it's older than variables_updated_at.
	variableUpdateTimes := []struct {
		ProfileUUID        string    `db:"profile_uuid"`
		VariablesUpdatedAt time.Time `db:"variables_updated_at"`
	}{}
	variableUpdateTimesStmt := `
	SELECT profile_uuid, variables_updated_at AS variables_updated_at
	FROM host_mdm_apple_profiles
	WHERE host_uuid = ? AND variables_updated_at IS NOT NULL
	`

	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &variableUpdateTimes, variableUpdateTimesStmt, host.UUID); err != nil {
		return nil, ctxerr.Wrap(ctx, err, fmt.Sprintf("getting expected profiles for host in team %d", teamID))
	}
	variableUpdateTimesByProfileUUID := make(map[string]time.Time, len(variableUpdateTimes))
	for _, r := range variableUpdateTimes {
		variableUpdateTimesByProfileUUID[r.ProfileUUID] = r.VariablesUpdatedAt
	}

	expectedProfilesByIdentifier := make(map[string]*fleet.ExpectedMDMProfile, len(rows))
	for _, r := range rows {
		if variableUpdateTime, ok := variableUpdateTimesByProfileUUID[r.ProfileUUID]; ok && variableUpdateTime.After(r.EarliestInstallDate) {
			r.EarliestInstallDate = variableUpdateTime
		}
		expectedProfilesByIdentifier[r.Identifier] = r
	}

	return expectedProfilesByIdentifier, nil
}

func (ds *Datastore) GetHostMDMProfilesRetryCounts(ctx context.Context, host *fleet.Host) ([]fleet.HostMDMProfileRetryCount, error) {
	const darwinStmt = `
SELECT
	profile_identifier,
	retries
FROM
	host_mdm_apple_profiles hmap
WHERE
	hmap.host_uuid = ?`

	const windowsStmt = `
SELECT
	profile_name,
	retries
FROM
	host_mdm_windows_profiles hmwp
WHERE
	hmwp.host_uuid = ?`

	var stmt string
	switch host.Platform {
	case "darwin", "ios", "ipados":
		stmt = darwinStmt
	case "windows":
		stmt = windowsStmt
	default:
		return nil, fmt.Errorf("unsupported platform %s", host.Platform)
	}

	var dest []fleet.HostMDMProfileRetryCount
	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &dest, stmt, host.UUID); err != nil {
		return nil, ctxerr.Wrap(ctx, err, fmt.Sprintf("getting retry counts for host %s", host.UUID))
	}

	return dest, nil
}

func (ds *Datastore) GetHostMDMProfileRetryCountByCommandUUID(ctx context.Context, host *fleet.Host, cmdUUID string) (fleet.HostMDMProfileRetryCount, error) {
	const darwinStmt = `
SELECT
	profile_identifier, retries
FROM
	host_mdm_apple_profiles hmap
WHERE
	hmap.host_uuid = ?
	AND hmap.command_uuid = ?`

	const windowsStmt = `
SELECT
	profile_uuid, retries
FROM
	host_mdm_windows_profiles hmwp
WHERE
	hmwp.host_uuid = ?
	AND hmwp.command_uuid = ?`

	var stmt string
	switch host.Platform {
	case "darwin", "ios", "ipados":
		stmt = darwinStmt
	case "windows":
		stmt = windowsStmt
	default:
		return fleet.HostMDMProfileRetryCount{}, fmt.Errorf("unsupported platform %s", host.Platform)
	}

	var dest fleet.HostMDMProfileRetryCount
	if err := sqlx.GetContext(ctx, ds.reader(ctx), &dest, stmt, host.UUID, cmdUUID); err != nil {
		if err == sql.ErrNoRows {
			return dest, notFound("HostMDMCommand").WithMessage(fmt.Sprintf("command uuid %s not found for host uuid %s", cmdUUID, host.UUID))
		}
		return dest, ctxerr.Wrap(ctx, err, fmt.Sprintf("getting retry count for host %s command uuid %s", host.UUID, cmdUUID))
	}

	return dest, nil
}

func batchSetProfileLabelAssociationsDB(
	ctx context.Context,
	tx sqlx.ExtContext,
	profileLabels []fleet.ConfigurationProfileLabel,
	profileUUIDsWithoutLabels []string,
	platform string,
) (updatedDB bool, err error) {
	if len(profileLabels)+len(profileUUIDsWithoutLabels) == 0 {
		return false, nil
	}

	var platformPrefix string
	switch platform {
	case "darwin":
		// map "darwin" to "apple" to be consistent with other
		// "platform-agnostic" datastore methods. We initially used "darwin"
		// because that's what hosts use (as the data is reported by osquery)
		// and sometimes we want to dynamically select a table based on host
		// data.
		platformPrefix = "apple"
	case "windows":
		platformPrefix = "windows"
	case "android":
		platformPrefix = "android"
	default:
		return false, fmt.Errorf("unsupported platform %s", platform)
	}

	// delete any profile+label tuple that is NOT in the list of provided tuples
	// but are associated with the provided profiles (so we don't delete
	// unrelated profile+label tuples)
	deleteStmt := `
	  DELETE FROM mdm_configuration_profile_labels
	  WHERE (%s_profile_uuid, label_id) NOT IN (%s) AND
	  %s_profile_uuid IN (?)
	`

	// used when only profileUUIDsWithoutLabels is provided, there are no
	// labels to keep, delete all labels for profiles in this list.
	deleteNoLabelStmt := `
	  DELETE FROM mdm_configuration_profile_labels
	  WHERE %s_profile_uuid IN (?)
	`

	upsertStmt := `
	  INSERT INTO mdm_configuration_profile_labels
              (%s_profile_uuid, label_id, label_name, exclude, require_all)
          VALUES
              %s
          ON DUPLICATE KEY UPDATE
              label_id = VALUES(label_id),
              exclude = VALUES(exclude),
			  require_all = VALUES(require_all)
	`

	selectStmt := `
		SELECT %s_profile_uuid as profile_uuid, label_id, label_name, exclude, require_all FROM mdm_configuration_profile_labels
		WHERE (%s_profile_uuid, label_name) IN (%s)
	`

	if len(profileLabels) == 0 {
		deleteNoLabelStmt = fmt.Sprintf(deleteNoLabelStmt, platformPrefix)
		deleteNoLabelStmt, args, err := sqlx.In(deleteNoLabelStmt, profileUUIDsWithoutLabels)
		if err != nil {
			return false, ctxerr.Wrap(ctx, err, "sqlx.In delete labels for profiles without labels")
		}

		var result sql.Result
		if result, err = tx.ExecContext(ctx, deleteNoLabelStmt, args...); err != nil {
			return false, ctxerr.Wrap(ctx, err, "deleting labels for profiles without labels")
		}
		if result != nil {
			rows, _ := result.RowsAffected()
			updatedDB = rows > 0
		}
		return updatedDB, nil
	}

	var (
		insertBuilder         strings.Builder
		selectOrDeleteBuilder strings.Builder
		selectParams          []any
		insertParams          []any
		deleteParams          []any

		setProfileUUIDs = make(map[string]struct{})
	)

	labelsToInsert := make(map[string]*fleet.ConfigurationProfileLabel, len(profileLabels))
	for i, pl := range profileLabels {
		labelsToInsert[fmt.Sprintf("%s\n%s", pl.ProfileUUID, pl.LabelName)] = &profileLabels[i]
		if i > 0 {
			insertBuilder.WriteString(",")
			selectOrDeleteBuilder.WriteString(",")
		}
		insertBuilder.WriteString("(?, ?, ?, ?, ?)")
		selectOrDeleteBuilder.WriteString("(?, ?)")
		selectParams = append(selectParams, pl.ProfileUUID, pl.LabelName)
		insertParams = append(insertParams, pl.ProfileUUID, pl.LabelID, pl.LabelName, pl.Exclude, pl.RequireAll)
		deleteParams = append(deleteParams, pl.ProfileUUID, pl.LabelID)

		setProfileUUIDs[pl.ProfileUUID] = struct{}{}
	}

	// Determine if we need to update the database
	var existingProfileLabels []fleet.ConfigurationProfileLabel
	err = sqlx.SelectContext(ctx, tx, &existingProfileLabels,
		fmt.Sprintf(selectStmt, platformPrefix, platformPrefix, selectOrDeleteBuilder.String()), selectParams...)
	if err != nil {
		return false, ctxerr.Wrap(ctx, err, "selecting existing profile labels")
	}

	updateNeeded := false
	if len(existingProfileLabels) == len(labelsToInsert) {
		for _, existing := range existingProfileLabels {
			toInsert, ok := labelsToInsert[fmt.Sprintf("%s\n%s", existing.ProfileUUID, existing.LabelName)]
			// The fleet.ConfigurationProfileLabel struct has no pointers, so we can use standard cmp.Equal
			if !ok || !cmp.Equal(existing, *toInsert) {
				updateNeeded = true
				break
			}
		}
	} else {
		updateNeeded = true
	}

	if updateNeeded {
		_, err := tx.ExecContext(ctx, fmt.Sprintf(upsertStmt, platformPrefix, insertBuilder.String()), insertParams...)
		if err != nil {
			if isChildForeignKeyError(err) {
				// one of the provided labels doesn't exist
				return false, foreignKey("mdm_configuration_profile_labels", fmt.Sprintf("(profile, label)=(%v)", insertParams))
			}

			return false, ctxerr.Wrap(ctx, err, "setting label associations for profile")
		}
		updatedDB = true
	}

	deleteStmt = fmt.Sprintf(deleteStmt, platformPrefix, selectOrDeleteBuilder.String(), platformPrefix)

	profUUIDs := make([]string, 0, len(setProfileUUIDs)+len(profileUUIDsWithoutLabels))
	for k := range setProfileUUIDs {
		profUUIDs = append(profUUIDs, k)
	}
	profUUIDs = append(profUUIDs, profileUUIDsWithoutLabels...)
	deleteArgs := deleteParams
	deleteArgs = append(deleteArgs, profUUIDs)

	deleteStmt, args, err := sqlx.In(deleteStmt, deleteArgs...)
	if err != nil {
		return false, ctxerr.Wrap(ctx, err, "sqlx.In delete labels for profiles")
	}
	var result sql.Result
	if result, err = tx.ExecContext(ctx, deleteStmt, args...); err != nil {
		return false, ctxerr.Wrap(ctx, err, "deleting labels for profiles")
	}
	if result != nil {
		rows, _ := result.RowsAffected()
		updatedDB = updatedDB || rows > 0
	}

	return updatedDB, nil
}

func (ds *Datastore) MDMGetEULAMetadata(ctx context.Context) (*fleet.MDMEULA, error) {
	// Currently, there can only be one EULA in the database, and we're
	// hardcoding it's id to be 1 in order to enforce this restriction.
	stmt := "SELECT name, created_at, token, sha256 FROM eulas WHERE id = 1"
	var eula fleet.MDMEULA
	if err := sqlx.GetContext(ctx, ds.reader(ctx), &eula, stmt); err != nil {
		if err == sql.ErrNoRows {
			return nil, ctxerr.Wrap(ctx, notFound("MDMEULA"))
		}
		return nil, ctxerr.Wrap(ctx, err, "get EULA metadata")
	}
	return &eula, nil
}

func (ds *Datastore) MDMGetEULABytes(ctx context.Context, token string) (*fleet.MDMEULA, error) {
	stmt := "SELECT name, bytes FROM eulas WHERE token = ?"
	var eula fleet.MDMEULA
	if err := sqlx.GetContext(ctx, ds.reader(ctx), &eula, stmt, token); err != nil {
		if err == sql.ErrNoRows {
			return nil, ctxerr.Wrap(ctx, notFound("MDMEULA"))
		}
		return nil, ctxerr.Wrap(ctx, err, "get EULA bytes")
	}
	return &eula, nil
}

func (ds *Datastore) MDMInsertEULA(ctx context.Context, eula *fleet.MDMEULA) error {
	// We're intentionally hardcoding the id to be 1 because we only want to
	// allow one EULA.
	stmt := `
          INSERT INTO eulas (id, name, bytes, token, sha256)
	  VALUES (1, ?, ?, ?, ?)
	`

	_, err := ds.writer(ctx).ExecContext(ctx, stmt, eula.Name, eula.Bytes, eula.Token, eula.Sha256)
	if err != nil {
		if IsDuplicate(err) {
			return ctxerr.Wrap(ctx, alreadyExists("MDMEULA", eula.Token))
		}
		return ctxerr.Wrap(ctx, err, "create EULA")
	}

	return nil
}

func (ds *Datastore) MDMDeleteEULA(ctx context.Context, token string) error {
	stmt := "DELETE FROM eulas WHERE token = ?"
	res, err := ds.writer(ctx).ExecContext(ctx, stmt, token)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "delete EULA")
	}

	deleted, _ := res.RowsAffected()
	if deleted != 1 {
		return ctxerr.Wrap(ctx, notFound("MDMEULA"))
	}
	return nil
}

func (ds *Datastore) GetHostCertAssociationsToExpire(ctx context.Context, expiryDays, limit int) ([]fleet.SCEPIdentityAssociation, error) {
	// TODO(roberto): this is not good because we don't have any indexes on
	// h.uuid, due to time constraints, I'm assuming that this
	// function is called with a relatively low amount of shas
	//
	// Note that we use GROUP BY because we can't guarantee unique entries
	// based on uuid in the hosts table.
	stmt, args, err := sqlx.In(`
SELECT
    h.uuid AS host_uuid,
    ncaa.sha256 AS sha256,
    COALESCE(MAX(hm.fleet_enroll_ref), '') AS enroll_reference,
    ne.enrolled_from_migration,
    ne.type
FROM (
    -- grab only the latest certificate associated with this device
    SELECT
        n1.id,
	n1.sha256,
	n1.cert_not_valid_after,
	n1.renew_command_uuid
    FROM
        nano_cert_auth_associations n1
    WHERE
        n1.sha256 = (
            SELECT
                n2.sha256
            FROM
                nano_cert_auth_associations n2
            WHERE
                n1.id = n2.id
            ORDER BY
                n2.created_at DESC,
                n2.sha256 ASC
            LIMIT 1
        )
) ncaa
JOIN
    hosts h ON h.uuid = ncaa.id
LEFT JOIN
    host_mdm hm ON hm.host_id = h.id
LEFT JOIN
    nano_enrollments ne ON ne.id = ncaa.id
WHERE
    ncaa.cert_not_valid_after BETWEEN '0000-00-00' AND DATE_ADD(CURDATE(), INTERVAL ? DAY)
    AND ncaa.renew_command_uuid IS NULL
    AND ne.enabled = 1
GROUP BY
    host_uuid, ncaa.sha256, ncaa.cert_not_valid_after
ORDER BY
    cert_not_valid_after ASC
LIMIT ?`, expiryDays, limit)
	if err != nil {
		return nil, ctxerr.Wrap(ctx, err, "building sqlx.In query")
	}

	var uuids []fleet.SCEPIdentityAssociation
	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &uuids, stmt, args...); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, ctxerr.Wrap(ctx, err, "get identity certs close to expiry")
	}
	return uuids, nil
}

func (ds *Datastore) SetCommandForPendingSCEPRenewal(ctx context.Context, assocs []fleet.SCEPIdentityAssociation, cmdUUID string) error {
	if len(assocs) == 0 {
		return nil
	}

	var sb strings.Builder
	args := make([]any, len(assocs)*3)
	for i, assoc := range assocs {
		sb.WriteString("(?, ?, ?),")
		args[i*3] = assoc.HostUUID
		args[i*3+1] = assoc.SHA256
		args[i*3+2] = cmdUUID
	}

	stmt := fmt.Sprintf(`
		INSERT INTO nano_cert_auth_associations (id, sha256, renew_command_uuid) VALUES %s
		ON DUPLICATE KEY UPDATE
			renew_command_uuid = VALUES(renew_command_uuid)
	`, strings.TrimSuffix(sb.String(), ","))

	return ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
		res, err := tx.ExecContext(ctx, stmt, args...)
		if err != nil {
			return fmt.Errorf("failed to update cert associations: %w", err)
		}

		// NOTE: we can't use insertOnDuplicateDidInsert because the
		// LastInsertId check only works tables that have an
		// auto-incrementing primary key. See notes in that function
		// and insertOnDuplicateDidUpdate to understand the mechanism.
		affected, _ := res.RowsAffected()
		if affected == 1 {
			return errors.New("this function can only be used to update existing associations")
		}

		return nil
	})
}

func (ds *Datastore) CleanSCEPRenewRefs(ctx context.Context, hostUUID string) error {
	stmt := `
	UPDATE nano_cert_auth_associations
	SET renew_command_uuid = NULL
	WHERE id = ?`

	res, err := ds.writer(ctx).ExecContext(ctx, stmt, hostUUID)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "cleaning SCEP renew references")
	}

	if rows, _ := res.RowsAffected(); rows == 0 {
		return ctxerr.Errorf(ctx, "nano association for host.uuid %s doesn't exist", hostUUID)
	}

	return nil
}

func (ds *Datastore) GetHostMDMProfileInstallStatus(ctx context.Context, hostUUID string, profUUID string) (fleet.MDMDeliveryStatus, error) {
	table, column, err := getTableAndColumnNameForHostMDMProfileUUID(profUUID)
	if err != nil {
		return "", ctxerr.Wrap(ctx, err, "getting table and column")
	}

	selectStmt := fmt.Sprintf(`
SELECT
	COALESCE(status, ?) as status
	FROM
	%s
WHERE
	operation_type = ?
	AND host_uuid = ?
	AND %s = ?
`, table, column)

	var status fleet.MDMDeliveryStatus
	if err := sqlx.GetContext(ctx, ds.writer(ctx), &status, selectStmt, fleet.MDMDeliveryPending, fleet.MDMOperationTypeInstall, hostUUID, profUUID); err != nil {
		if err == sql.ErrNoRows {
			return "", notFound("HostMDMProfile").WithMessage("unable to match profile to host")
		}
		return "", ctxerr.Wrap(ctx, err, "get MDM profile status")
	}
	return status, nil
}

func (ds *Datastore) ResendHostMDMProfile(ctx context.Context, hostUUID string, profUUID string) error {
	table, column, err := getTableAndColumnNameForHostMDMProfileUUID(profUUID)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "getting table and column")
	}

	// update the status to NULL to trigger resending on the next cron run
	updateStmt := fmt.Sprintf(`UPDATE %s SET status = NULL WHERE host_uuid = ? AND %s = ?`, table, column)

	return ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
		res, err := tx.ExecContext(ctx, updateStmt, hostUUID, profUUID)
		if err != nil {
			return ctxerr.Wrap(ctx, err, "resending host MDM profile")
		}
		if rows, _ := res.RowsAffected(); rows == 0 {
			// this should never happen, log for debugging
			level.Debug(ds.logger).Log("msg", "resend profile status not updated", "host_uuid", hostUUID, "profile_uuid", profUUID)
		}

		return nil
	})
}

func getTableAndColumnNameForHostMDMProfileUUID(profUUID string) (table, column string, err error) {
	switch {
	case strings.HasPrefix(profUUID, fleet.MDMAppleDeclarationUUIDPrefix):
		return "host_mdm_apple_declarations", "declaration_uuid", nil
	case strings.HasPrefix(profUUID, fleet.MDMAppleProfileUUIDPrefix):
		return "host_mdm_apple_profiles", "profile_uuid", nil
	case strings.HasPrefix(profUUID, fleet.MDMWindowsProfileUUIDPrefix):
		return "host_mdm_windows_profiles", "profile_uuid", nil
	case strings.HasPrefix(profUUID, fleet.MDMAndroidProfileUUIDPrefix):
		return "host_mdm_android_profiles", "profile_uuid", nil
	default:
		return "", "", fmt.Errorf("invalid profile UUID prefix %s", profUUID)
	}
}

func (ds *Datastore) AreHostsConnectedToFleetMDM(ctx context.Context, hosts []*fleet.Host) (map[string]bool, error) {
	var (
		appleUUIDs []any
		winUUIDs   []any
	)

	res := make(map[string]bool, len(hosts))
	for _, h := range hosts {
		switch h.Platform {
		case "darwin", "ipados", "ios":
			appleUUIDs = append(appleUUIDs, h.UUID)
		case "windows":
			winUUIDs = append(winUUIDs, h.UUID)
		}
		res[h.UUID] = false
	}

	setConnectedUUIDs := func(stmt string, uuids []any, mp map[string]bool) error {
		var res []string

		if len(uuids) > 0 {
			stmt, args, err := sqlx.In(stmt, uuids)
			if err != nil {
				return ctxerr.Wrap(ctx, err, "building sqlx.In statement")
			}
			err = sqlx.SelectContext(ctx, ds.reader(ctx), &res, stmt, args...)
			if err != nil {
				return ctxerr.Wrap(ctx, err, "retrieving hosts connected to fleet")
			}
		}

		for _, uuid := range res {
			mp[uuid] = true
		}

		return nil
	}

	// NOTE: if you change any of the conditions in this query, please
	// update the `hostMDMSelect` constant too, which has a
	// `connected_to_fleet` condition, any relevant filters, and the
	// query used in isAppleHostConnectedToFleetMDM.
	const appleStmt = `
	  SELECT ne.id
	  FROM nano_enrollments ne
	    JOIN hosts h ON h.uuid = ne.id
	    JOIN host_mdm hm ON hm.host_id = h.id
	  WHERE ne.id IN (?)
	    AND ne.enabled = 1
	    AND ne.type IN ('Device', 'User Enrollment (Device)')
	    AND hm.enrolled = 1
	`
	if err := setConnectedUUIDs(appleStmt, appleUUIDs, res); err != nil {
		return nil, err
	}

	// NOTE: if you change any of the conditions in this query, please
	// update the `hostMDMSelect` constant too, which has a
	// `connected_to_fleet` condition, and any relevant filters, and the
	// query used in isWindowsHostConnectedToFleetMDM.
	const winStmt = `
	  SELECT mwe.host_uuid
	  FROM mdm_windows_enrollments mwe
	    JOIN hosts h ON h.uuid = mwe.host_uuid
	    JOIN host_mdm hm ON hm.host_id = h.id
	  WHERE mwe.host_uuid IN (?)
	    AND mwe.device_state = '` + microsoft_mdm.MDMDeviceStateEnrolled + `'
	    AND hm.enrolled = 1
	`
	if err := setConnectedUUIDs(winStmt, winUUIDs, res); err != nil {
		return nil, err
	}

	return res, nil
}

func (ds *Datastore) IsHostConnectedToFleetMDM(ctx context.Context, host *fleet.Host) (bool, error) {
	switch host.Platform {
	case "windows":
		return isWindowsHostConnectedToFleetMDM(ctx, ds.reader(ctx), host)
	case "darwin", "ipados", "ios":
		return isAppleHostConnectedToFleetMDM(ctx, ds.reader(ctx), host)
	case "android":
		// Android hosts can only enroll via MDM
		return isAndroidHostConnectedToFleetMDM(ctx, ds.reader(ctx), host)
	default:
		return false, nil
	}
}

func batchSetProfileVariableAssociationsDB(
	ctx context.Context,
	tx sqlx.ExtContext,
	profileVariablesByUUID []fleet.MDMProfileUUIDFleetVariables,
	platform string,
) (didUpdate bool, err error) {
	if len(profileVariablesByUUID) == 0 {
		return false, nil
	}

	var platformPrefix string
	switch platform {
	case "darwin":
		platformPrefix = "apple"
	case "windows":
		platformPrefix = "windows"
	case "android":
		return false, nil // Early return here, to avoid failing but still utilizing the shared batchSet method.
	default:
		return false, fmt.Errorf("unsupported platform %s", platform)
	}

	// collect the profile uuids to clear
	profileUUIDsToDelete := make([]string, 0, len(profileVariablesByUUID))
	// small optimization - if there are no variables to insert, we can stop here
	var varsToSet bool
	for _, profVars := range profileVariablesByUUID {
		profileUUIDsToDelete = append(profileUUIDsToDelete, profVars.ProfileUUID)
		if len(profVars.FleetVariables) > 0 {
			varsToSet = true
		}
	}

	// delete variables associated with those profiles
	clearVarsForProfilesStmt := fmt.Sprintf(`DELETE FROM mdm_configuration_profile_variables WHERE %s_profile_uuid IN (?)`, platformPrefix)
	clearVarsForProfilesStmt, args, err := sqlx.In(clearVarsForProfilesStmt, profileUUIDsToDelete)
	if err != nil {
		return false, ctxerr.Wrap(ctx, err, "sqlx.In delete variables for profiles")
	}
	var res sql.Result
	if res, err = tx.ExecContext(ctx, clearVarsForProfilesStmt, args...); err != nil {
		return false, ctxerr.Wrap(ctx, err, "deleting variables for profiles")
	}
	rowsDeleted, err := res.RowsAffected()
	if err != nil {
		return false, ctxerr.Wrap(ctx, err, "rows affected for deleting variables for profiles")
	}

	if !varsToSet {
		return rowsDeleted > 0, nil
	}

	// load fleet variables to map them to their IDs
	type varDef struct {
		ID       uint   `db:"id"`
		Name     string `db:"name"`
		IsPrefix bool   `db:"is_prefix"`
	}

	var varDefs []varDef
	const varsStmt = `SELECT id, name, is_prefix FROM fleet_variables`
	if err := sqlx.SelectContext(ctx, tx, &varDefs, varsStmt); err != nil {
		return false, fmt.Errorf("failed to load fleet variables: %w", err)
	}

	// map the variables to their IDs (this looks terrible with the nested fors
	// but those are all very small "n" - single-digit vars by profile and same
	// in varDefs, so this is more efficient than building lookup maps).
	type profVarTuple struct {
		ProfileUUID string
		VarID       uint
	}
	profVars := make([]profVarTuple, 0, len(profileVariablesByUUID))
	for _, pv := range profileVariablesByUUID {
		for _, v := range pv.FleetVariables {
			// variables received here do not have the FLEET_VAR_ prefix, but variables
			// in the fleet_variables table do.
			varWithPrefix := "FLEET_VAR_" + string(v)
			for _, def := range varDefs {
				if !def.IsPrefix && def.Name == varWithPrefix {
					profVars = append(profVars, profVarTuple{pv.ProfileUUID, def.ID})
					break
				}
				if def.IsPrefix && strings.HasPrefix(varWithPrefix, def.Name) {
					profVars = append(profVars, profVarTuple{pv.ProfileUUID, def.ID})
					break
				}
			}
		}
	}

	const batchSize = 1000 // number of parameters is this times number of placeholders
	generateValueArgs := func(p profVarTuple) (string, []any) {
		valuePart := "(?, ?),"
		args := []any{p.ProfileUUID, p.VarID}
		return valuePart, args
	}

	executeUpsertBatch := func(valuePart string, args []any) error {
		stmt := fmt.Sprintf(`
			INSERT INTO mdm_configuration_profile_variables (
				%s_profile_uuid,
				fleet_variable_id
			)
			VALUES %s
			ON DUPLICATE KEY UPDATE
				fleet_variable_id = VALUES(fleet_variable_id)
		`, platformPrefix, strings.TrimSuffix(valuePart, ","))

		_, err := tx.ExecContext(ctx, stmt, args...)
		return err
	}

	err = batchProcessDB(profVars, batchSize, generateValueArgs, executeUpsertBatch)
	if err != nil {
		return false, ctxerr.Wrap(ctx, err, "upserting profile variables")
	}
	return true, nil
}

func (ds *Datastore) BatchResendMDMProfileToHosts(ctx context.Context, profileUUID string, filters fleet.BatchResendMDMProfileFilters) (int64, error) {
	table, column, err := getTableAndColumnNameForHostMDMProfileUUID(profileUUID)
	if err != nil {
		return 0, ctxerr.Wrap(ctx, err, "getting table and column")
	}

	// update the status to NULL to trigger resending on the next cron run
	updateStmt := fmt.Sprintf(`UPDATE %s SET status = NULL WHERE %s = ? AND status = ?`, table, column)

	var count int64
	err = ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
		res, err := tx.ExecContext(ctx, updateStmt, profileUUID, filters.ProfileStatus)
		if err != nil {
			return ctxerr.Wrap(ctx, err, "resending MDM profile on hosts")
		}
		count, _ = res.RowsAffected()
		return nil
	})
	return count, err
}

func (ds *Datastore) GetMDMConfigProfileStatus(ctx context.Context, profileUUID string) (fleet.MDMConfigProfileStatus, error) {
	switch {
	case strings.HasPrefix(profileUUID, fleet.MDMAppleProfileUUIDPrefix):
		return ds.getAppleMDMConfigProfileStatus(ctx, profileUUID)
	case strings.HasPrefix(profileUUID, fleet.MDMAppleDeclarationUUIDPrefix):
		return ds.getAppleMDMDeclarationStatus(ctx, profileUUID)
	case strings.HasPrefix(profileUUID, fleet.MDMWindowsProfileUUIDPrefix):
		return ds.getWindowsMDMConfigProfileStatus(ctx, profileUUID)
	case strings.HasPrefix(profileUUID, fleet.MDMAndroidProfileUUIDPrefix):
		return ds.getAndroidMDMConfigProfileStatus(ctx, profileUUID)
	default:
		return fleet.MDMConfigProfileStatus{}, ctxerr.Wrap(ctx, notFound("ConfigurationProfile").WithName(profileUUID))
	}
}

func (ds *Datastore) getAndroidMDMConfigProfileStatus(ctx context.Context, profileUUID string) (fleet.MDMConfigProfileStatus, error) {
	var counts fleet.MDMConfigProfileStatus

	stmt := `
SELECT
	CASE
		WHEN hmap.status = :status_failed THEN
			'failed'
		WHEN COALESCE(hmap.status, :status_pending) = :status_pending THEN
			'pending'
		WHEN hmap.status = :status_verifying THEN
			'verifying'
		WHEN hmap.status = :status_verified THEN
			'verified'
		ELSE
			''
	END AS final_status,
	SUM(1) AS count
FROM
	hosts h
	JOIN host_mdm hmdm ON h.id = hmdm.host_id
	JOIN android_devices ad ON h.id=ad.host_id
	JOIN host_mdm_android_profiles hmap ON hmap.host_uuid = h.uuid
WHERE
	h.platform = 'android' AND
	hmdm.enrolled = 1 AND
	hmap.profile_uuid = :profile_uuid
GROUP BY
	final_status`

	stmt, args, err := sqlx.Named(stmt, map[string]any{
		"status_failed":    fleet.MDMDeliveryFailed,
		"status_pending":   fleet.MDMDeliveryPending,
		"status_verifying": fleet.MDMDeliveryVerifying,
		"status_verified":  fleet.MDMDeliveryVerified,
		"profile_uuid":     profileUUID,
	})
	if err != nil {
		return counts, ctxerr.Wrap(ctx, err, "prepare arguments with sqlx.Named")
	}

	var rows []statusCounts
	err = sqlx.SelectContext(ctx, ds.reader(ctx), &rows, stmt, args...)
	if err != nil {
		return counts, err
	}

	for _, row := range rows {
		switch row.Status {
		case string(fleet.MDMDeliveryFailed):
			counts.Failed = row.Count
		case string(fleet.MDMDeliveryPending):
			counts.Pending += row.Count
		case string(fleet.MDMDeliveryVerifying):
			counts.Verifying = row.Count
		case string(fleet.MDMDeliveryVerified):
			counts.Verified = row.Count
		case "":
			level.Debug(ds.logger).Log("msg", fmt.Sprintf("counted %d android hosts for profile %s with mdm turned on but no profiles", row.Count, profileUUID))
		default:
			return counts, ctxerr.New(ctx, fmt.Sprintf("unexpected mdm android status count: status=%s, count=%d", row.Status, row.Count))
		}
	}
	return counts, nil
}

func (ds *Datastore) getWindowsMDMConfigProfileStatus(ctx context.Context, profileUUID string) (fleet.MDMConfigProfileStatus, error) {
	var counts fleet.MDMConfigProfileStatus

	stmt := `
SELECT
	CASE
		WHEN hmwp.status = :status_failed THEN
			'failed'
		WHEN COALESCE(hmwp.status, :status_pending) = :status_pending THEN
			'pending'
		WHEN hmwp.status = :status_verifying THEN
			'verifying'
		WHEN hmwp.status = :status_verified THEN
			'verified'
		ELSE
			''
	END AS final_status,
	SUM(1) AS count
FROM
	hosts h
	JOIN host_mdm hmdm ON h.id = hmdm.host_id
	JOIN mdm_windows_enrollments mwe ON h.uuid = mwe.host_uuid
	JOIN host_mdm_windows_profiles hmwp ON hmwp.host_uuid = h.uuid
WHERE
	mwe.device_state = :device_state_enrolled AND
	h.platform = 'windows' AND
	hmdm.is_server = 0 AND
	hmdm.enrolled = 1 AND
	hmwp.profile_uuid = :profile_uuid
GROUP BY
	final_status`

	stmt, args, err := sqlx.Named(stmt, map[string]any{
		"status_failed":         fleet.MDMDeliveryFailed,
		"status_pending":        fleet.MDMDeliveryPending,
		"status_verifying":      fleet.MDMDeliveryVerifying,
		"status_verified":       fleet.MDMDeliveryVerified,
		"device_state_enrolled": microsoft_mdm.MDMDeviceStateEnrolled,
		"profile_uuid":          profileUUID,
	})
	if err != nil {
		return counts, ctxerr.Wrap(ctx, err, "prepare arguments with sqlx.Named")
	}

	var rows []statusCounts
	err = sqlx.SelectContext(ctx, ds.reader(ctx), &rows, stmt, args...)
	if err != nil {
		return counts, err
	}

	// Note that hosts with "BitLocker action required" are counted as pending.
	for _, row := range rows {
		switch row.Status {
		case "failed":
			counts.Failed = row.Count
		case "pending":
			counts.Pending += row.Count
		case "verifying":
			counts.Verifying = row.Count
		case "verified":
			counts.Verified = row.Count
		case "":
			level.Debug(ds.logger).Log("msg", fmt.Sprintf("counted %d windows hosts for profile %s with mdm turned on but no profiles", row.Count, profileUUID))
		default:
			return counts, ctxerr.New(ctx, fmt.Sprintf("unexpected mdm windows status count: status=%s, count=%d", row.Status, row.Count))
		}
	}
	return counts, nil
}

func (ds *Datastore) getAppleMDMConfigProfileStatus(ctx context.Context, profileUUID string) (fleet.MDMConfigProfileStatus, error) {
	var counts fleet.MDMConfigProfileStatus

	// NOTE: the case computation of the status must follow the same logic as in
	// sqlJoinMDMAppleProfilesStatus (for non-file-vault, since this is for
	// custom settings).
	stmt := `
SELECT
	COUNT(id) AS count,
	CASE
		WHEN hmap.status = :status_failed THEN
			'failed'
		WHEN COALESCE(hmap.status, :status_pending) = :status_pending THEN
			'pending'
		WHEN hmap.status = :status_verifying THEN
			'verifying'
		WHEN hmap.status = :status_verified THEN
			'verified'
	END AS final_status
FROM
	hosts h
	JOIN host_mdm_apple_profiles hmap ON h.uuid = hmap.host_uuid
WHERE
	platform IN ('darwin', 'ios', 'ipados') AND
	hmap.profile_uuid = :profile_uuid AND
	( hmap.status NOT IN (:status_verified, :status_verifying) OR hmap.operation_type = :operation_install )
GROUP BY
	final_status HAVING final_status IS NOT NULL`

	stmt, args, err := sqlx.Named(stmt, map[string]any{
		"status_failed":     fleet.MDMDeliveryFailed,
		"status_pending":    fleet.MDMDeliveryPending,
		"status_verifying":  fleet.MDMDeliveryVerifying,
		"status_verified":   fleet.MDMDeliveryVerified,
		"operation_install": fleet.MDMOperationTypeInstall,
		"profile_uuid":      profileUUID,
	})
	if err != nil {
		return counts, ctxerr.Wrap(ctx, err, "prepare arguments with sqlx.Named")
	}

	var dest []struct {
		Count  uint   `db:"count"`
		Status string `db:"final_status"`
	}

	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &dest, stmt, args...); err != nil {
		return counts, err
	}

	byStatus := make(map[string]uint)
	for _, s := range dest {
		if _, ok := byStatus[s.Status]; ok {
			return counts, fmt.Errorf("duplicate status %s", s.Status)
		}
		byStatus[s.Status] = s.Count
	}

	for s, c := range byStatus {
		switch fleet.MDMDeliveryStatus(s) {
		case fleet.MDMDeliveryFailed:
			counts.Failed = c
		case fleet.MDMDeliveryPending:
			counts.Pending = c
		case fleet.MDMDeliveryVerifying:
			counts.Verifying = c
		case fleet.MDMDeliveryVerified:
			counts.Verified = c
		default:
			return counts, fmt.Errorf("unknown status %s", s)
		}
	}

	return counts, nil
}

func (ds *Datastore) getAppleMDMDeclarationStatus(ctx context.Context, declUUID string) (fleet.MDMConfigProfileStatus, error) {
	var counts fleet.MDMConfigProfileStatus

	// NOTE: the case computation of the status must follow the same logic as in
	// sqlJoinMDMAppleDeclarationsStatus.
	stmt := `
SELECT
	COUNT(id) AS count,
	CASE
		WHEN hmad.status = :status_failed THEN
			'failed'
		WHEN COALESCE(hmad.status, :status_pending) = :status_pending THEN
			'pending'
		WHEN hmad.status = :status_verifying THEN
			'verifying'
		WHEN hmad.status = :status_verified THEN
			'verified'
	END AS final_status
FROM
	hosts h
	JOIN host_mdm_apple_declarations hmad ON h.uuid = hmad.host_uuid
WHERE
	h.platform IN ('darwin', 'ios', 'ipados') AND
	( hmad.status NOT IN (:status_verified, :status_verifying) OR hmad.operation_type = :operation_install ) AND
	hmad.declaration_uuid = :declaration_uuid
GROUP BY
	final_status HAVING final_status IS NOT NULL`

	stmt, args, err := sqlx.Named(stmt, map[string]any{
		"status_failed":     fleet.MDMDeliveryFailed,
		"status_pending":    fleet.MDMDeliveryPending,
		"status_verifying":  fleet.MDMDeliveryVerifying,
		"status_verified":   fleet.MDMDeliveryVerified,
		"operation_install": fleet.MDMOperationTypeInstall,
		"declaration_uuid":  declUUID,
	})
	if err != nil {
		return counts, ctxerr.Wrap(ctx, err, "prepare arguments with sqlx.Named")
	}

	var dest []struct {
		Count  uint   `db:"count"`
		Status string `db:"final_status"`
	}

	if err := sqlx.SelectContext(ctx, ds.reader(ctx), &dest, stmt, args...); err != nil {
		return counts, err
	}

	byStatus := make(map[string]uint)
	for _, s := range dest {
		if _, ok := byStatus[s.Status]; ok {
			return counts, fmt.Errorf("duplicate status %s", s.Status)
		}
		byStatus[s.Status] = s.Count
	}

	for s, c := range byStatus {
		switch fleet.MDMDeliveryStatus(s) {
		case fleet.MDMDeliveryFailed:
			counts.Failed = c
		case fleet.MDMDeliveryPending:
			counts.Pending = c
		case fleet.MDMDeliveryVerifying:
			counts.Verifying = c
		case fleet.MDMDeliveryVerified:
			counts.Verified = c
		default:
			return counts, fmt.Errorf("unknown status %s", s)
		}
	}

	return counts, nil
}

func (ds *Datastore) IsHostPendingMDMInstallVerification(ctx context.Context, hostUUID string) (bool, error) {
	stmt := `
SELECT EXISTS (
	SELECT 1
    FROM host_mdm_commands hmc
    JOIN hosts h ON hmc.host_id = h.id
    WHERE
		h.uuid = ? AND
		hmc.command_type = ?
) AS exists_flag
`
	var exists bool
	if err := sqlx.GetContext(ctx, ds.reader(ctx), &exists, stmt, hostUUID, fleet.VerifySoftwareInstallVPPPrefix); err != nil {
		return false, ctxerr.Wrap(ctx, err, "check for acknowledged mdm command by host")
	}
	return exists, nil
}

type batchSetAssociationCurrentProfile struct {
	ProfileUUID string `db:"profile_uuid"`
	Name        string `db:"name"`
}

type BatchSetAssociationIncomingProfile struct {
	Name             string // Identifier or name depending on Platform.
	ProfileUUID      string
	LabelsIncludeAll []fleet.ConfigurationProfileLabel
	LabelsIncludeAny []fleet.ConfigurationProfileLabel
	LabelsExcludeAny []fleet.ConfigurationProfileLabel
}

// batchSetAssociations handles setting label and variable associations for all types of platform profiles.
func (ds *Datastore) batchSetLabelAndVariableAssociations(ctx context.Context, tx sqlx.ExtContext, platform string, teamID *uint, incomingProfiles []*BatchSetAssociationIncomingProfile, profilesVariablesByIdentifier []fleet.MDMProfileIdentifierFleetVariables) (updatedLabels bool, err error) {
	if len(incomingProfiles) == 0 {
		return false, nil // Do nothing on empty incoming profiles.
	}

	var currentProfilesQuery string

	// Set platform specific variables here to use later.
	switch platform {
	case "darwin":
		currentProfilesQuery = `SELECT profile_uuid, identifier as name FROM mdm_apple_configuration_profiles WHERE team_id = ? AND identifier IN (?)`
	case "windows":
		currentProfilesQuery = `SELECT profile_uuid, name FROM mdm_windows_configuration_profiles WHERE team_id = ? AND name IN (?)`
	case "android":
		currentProfilesQuery = `SELECT profile_uuid, name FROM mdm_android_configuration_profiles WHERE team_id = ? AND name IN (?)`
	default:
		return false, ctxerr.Errorf(ctx, "unsupported platform %q", platform)
	}

	var profTeamID uint
	if teamID != nil {
		profTeamID = *teamID
	}

	var incomingNames []string
	incomingProfilesMap := make(map[string]*BatchSetAssociationIncomingProfile)
	for _, p := range incomingProfiles {
		incomingNames = append(incomingNames, p.Name)
		incomingProfilesMap[p.Name] = p
	}
	stmt, args, err := sqlx.In(currentProfilesQuery, profTeamID, incomingNames)
	if err != nil {
		return false, ctxerr.Wrap(ctx, err, "prepare current profiles query")
	}

	// A list of all new and updated profiles
	var currentProfiles []*batchSetAssociationCurrentProfile
	if err := sqlx.SelectContext(ctx, tx, &currentProfiles, stmt, args...); err != nil {
		return false, ctxerr.Wrap(ctx, err, "select current profiles")
	}

	incomingLabels := []fleet.ConfigurationProfileLabel{}
	var profsWithoutLabels []string

	for _, currentProfile := range currentProfiles {
		incomingProf, ok := incomingProfilesMap[currentProfile.Name]
		if !ok {
			return false, ctxerr.Errorf(ctx, "profile %q is in the database but was not incoming", currentProfile.Name)
		}

		var profHasLabel bool
		for _, label := range incomingProf.LabelsIncludeAll {
			label.ProfileUUID = currentProfile.ProfileUUID
			label.Exclude = false
			label.RequireAll = true
			incomingLabels = append(incomingLabels, label)
			profHasLabel = true
		}
		for _, label := range incomingProf.LabelsIncludeAny {
			label.ProfileUUID = currentProfile.ProfileUUID
			label.Exclude = false
			label.RequireAll = false
			incomingLabels = append(incomingLabels, label)
			profHasLabel = true
		}
		for _, label := range incomingProf.LabelsExcludeAny {
			label.ProfileUUID = currentProfile.ProfileUUID
			label.Exclude = true
			label.RequireAll = false
			incomingLabels = append(incomingLabels, label)
			profHasLabel = true
		}
		if !profHasLabel {
			profsWithoutLabels = append(profsWithoutLabels, currentProfile.ProfileUUID)
		}
	}

	var didUpdateLabels bool
	if didUpdateLabels, err = batchSetProfileLabelAssociationsDB(ctx, tx, incomingLabels, profsWithoutLabels,
		platform); err != nil {
		return false, ctxerr.Wrap(ctx, err, fmt.Sprintf("inserting %s profile label associations", platform))
	}

	// save fleet variables associated with Windows profiles (both new and updated)
	// Note: currentProfiles contains all incoming profiles (new AND updated), not just new ones
	// Process ALL profiles to ensure stale variable associations are cleared for profiles that no longer have variables
	profileVariablesByName := make(map[string][]fleet.FleetVarName, len(profilesVariablesByIdentifier))
	for _, pv := range profilesVariablesByIdentifier {
		profileVariablesByName[pv.Identifier] = pv.FleetVariables
	}

	// collect ALL profile UUIDs, including those without variables (to clear stale associations)
	var profilesVarsToUpsert []fleet.MDMProfileUUIDFleetVariables
	for _, p := range currentProfiles {
		vars := profileVariablesByName[p.Name] // defaults to nil/empty slice if not found
		// Include every profile, even those without variables, so the helper can clear old associations
		profilesVarsToUpsert = append(profilesVarsToUpsert, fleet.MDMProfileUUIDFleetVariables{
			ProfileUUID:    p.ProfileUUID,
			FleetVariables: vars, // may be empty/nil, which will clear associations
		})
	}

	if len(profilesVarsToUpsert) > 0 {
		var didUpdateVariableAssociations bool
		if didUpdateVariableAssociations, err = batchSetProfileVariableAssociationsDB(ctx, tx, profilesVarsToUpsert, platform); err != nil {
			return false, ctxerr.Wrap(ctx, err, fmt.Sprintf("inserting %s profile variable associations", platform))
		}

		return didUpdateVariableAssociations, nil
	}

	return didUpdateLabels, nil
}

func reconcileHostEmailsFromMdmIdpAccountsDB(ctx context.Context, tx sqlx.ExtContext, logger log.Logger, hostID uint) (*fleet.MDMIdPAccount, error) {
	idp, err := getMDMIdPAccountByHostID(ctx, tx, logger, hostID)
	if err != nil {
		return nil, ctxerr.Wrap(ctx, err, "get host mdm idp account email")
	}

	var hostEmails []fleet.HostDeviceMapping
	selectStmt := `SELECT id, host_id, email, source FROM host_emails WHERE host_id = ? AND source = ?`
	if err := sqlx.SelectContext(ctx, tx, &hostEmails, selectStmt, hostID, fleet.DeviceMappingMDMIdpAccounts); err != nil {
		return nil, ctxerr.Wrap(ctx, err, "get host_emails")
	}

	// TODO: discuss email vs. username with Victor
	var idpEmail, idpAccountUUID string
	if idp != nil {
		idpEmail = idp.Email
		idpAccountUUID = idp.UUID
	}

	// if we don't have idp info, we can just delete any prior host mdm idp account emails
	if idpEmail == "" {
		if len(hostEmails) == 0 {
			// nothing to do
			level.Info(logger).Log("msg", "reconcile host emails: no mdm idp account and no host emails", "host_id", hostID, "account_uuid", idpAccountUUID)
			return nil, nil
		}
		// delete any prior host mdm idp account emails
		delStmt := "DELETE FROM host_emails WHERE host_id = ? AND source = ?"
		if _, err := tx.ExecContext(ctx, delStmt, hostID, fleet.DeviceMappingMDMIdpAccounts); err != nil {
			return nil, ctxerr.Wrap(ctx, err, "delete host_emails")
		}
		return idp, nil
	}

	// analyze existing host emails to see if we have a match; we also want to handle potential
	// duplicates because we don't have good constraints on the host_emails table
	hits, misses := []fleet.HostDeviceMapping{}, []fleet.HostDeviceMapping{}
	for _, he := range hostEmails {
		if he.Email == idp.Email {
			hits = append(hits, he)
		} else {
			misses = append(misses, he)
		}
	}

	maxCapacity := len(misses)
	if len(hits) > 1 {
		maxCapacity += len(hits) - 1
	}
	idsToDelete := make([]uint, 0, maxCapacity)
	if len(misses) > 0 {
		// log the emails we'll be deleting
		msg := "reconcile host emails: deleting emails"
		for _, m := range misses {
			idsToDelete = append(idsToDelete, m.ID)
			msg += fmt.Sprintf(" %s", m.Email)
		}
		level.Info(logger).Log("msg", msg, "host_id", hostID)
	}

	var idToUpdate uint
	if len(hits) > 0 {
		// if we have more than one hit, we'll just update the first one
		idToUpdate = hits[0].ID
	}
	if len(hits) > 1 {
		// this should not happen, but if it does we want to know about it
		level.Info(logger).Log("msg", "reconcile host emails: found duplicate mdm idp account host email", "host_id", hostID, "email", idp.Email, "account_uuid", idp.UUID)
		for _, h := range hits[1:] {
			idsToDelete = append(idsToDelete, h.ID) // we'll delete all but the first
		}
	}

	if len(idsToDelete) > 0 {
		// perform the delete
		stmt, args, err := sqlx.In("DELETE FROM host_emails WHERE id IN (?)", idsToDelete)
		if err != nil {
			return nil, ctxerr.Wrap(ctx, err, "prepare delete host_emails arguments")
		}
		if _, err := tx.ExecContext(ctx, stmt, args...); err != nil {
			return nil, ctxerr.Wrap(ctx, err, "delete host_emails")
		}
	}

	if idToUpdate != 0 {
		// perform the update
		level.Info(logger).Log("msg", "reconcile host emails: update host mdm idp account email", "host_id", hostID, "email", idpEmail)
		updateStmt := "UPDATE host_emails SET email = ? WHERE id = ?"
		if _, err := tx.ExecContext(ctx, updateStmt, idpEmail, idToUpdate); err != nil {
			return nil, ctxerr.Wrap(ctx, err, "update host_emails")
		}
		return idp, nil
	}

	// insert new email
	level.Info(logger).Log("msg", "reconcile host emails: insert host mdm idp account email", "host_id", hostID, "email", idpEmail, "account_uuid", idp.UUID)
	insStmt := "INSERT INTO host_emails (email, host_id, source) VALUES (?, ?, ?)"
	if _, err := tx.ExecContext(ctx, insStmt, idpEmail, hostID, fleet.DeviceMappingMDMIdpAccounts); err != nil {
		return nil, ctxerr.Wrap(ctx, err, "insert host_emails")
	}

	return idp, nil
}

func getMDMIdPAccountByHostID(ctx context.Context, q sqlx.QueryerContext, logger log.Logger, hostID uint) (*fleet.MDMIdPAccount, error) {
	stmt := `SELECT account_uuid FROM host_mdm_idp_accounts WHERE host_uuid = (SELECT uuid FROM hosts WHERE id = ?)`
	var dest []string
	if err := sqlx.SelectContext(ctx, q, &dest, stmt, hostID); err != nil {
		return nil, ctxerr.Wrap(ctx, err, "select host_mdm_idp_accounts")
	}

	var acctUUID string
	switch {
	case len(dest) == 0:
		// TODO: consider falling back to the legacy enroll ref
		level.Info(logger).Log("msg", "get host mdm idp accounts: no account found", "host_id", hostID)
	default:
		if len(dest) > 1 {
			// this should not happen, but if it does we want to know about it
			level.Info(logger).Log("msg", "get host mdm idp accounts: found multiple accounts", "host_id", hostID, "acct_uuids", fmt.Sprintf("%+v", dest))
		}
		acctUUID = dest[0]
	}

	if acctUUID == "" {
		return nil, nil
	}

	var idp fleet.MDMIdPAccount
	stmt = `SELECT uuid, username, fullname, email FROM mdm_idp_accounts WHERE uuid = ?`
	if err := sqlx.GetContext(ctx, q, &idp, stmt, acctUUID); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil // TODO: maybe return a not found error?
		}
		return nil, ctxerr.Wrap(ctx, err, "get host mdm idp account")
	}

	return &idp, nil
}

func (ds *Datastore) CleanUpMDMManagedCertificates(ctx context.Context) error {
	_, err := ds.writer(ctx).ExecContext(ctx, `
	DELETE hmmc FROM host_mdm_managed_certificates hmmc
LEFT JOIN host_mdm_apple_profiles hmap ON hmmc.host_uuid = hmap.host_uuid
    AND hmmc.profile_uuid = hmap.profile_uuid
LEFT JOIN host_mdm_windows_profiles hwmp ON hmmc.host_uuid = hwmp.host_uuid
    AND hmmc.profile_uuid = hwmp.profile_uuid
WHERE
    hmap.host_uuid IS NULL
    AND hwmp.host_uuid IS NULL`)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "clean up mdm certificate profiles")
	}
	return nil
}

func (ds *Datastore) BulkUpsertMDMManagedCertificates(ctx context.Context, payload []*fleet.MDMManagedCertificate) error {
	if len(payload) == 0 {
		return nil
	}

	executeUpsertBatch := func(valuePart string, args []any) error {
		stmt := fmt.Sprintf(`
	    INSERT INTO host_mdm_managed_certificates (
              host_uuid,
              profile_uuid,
              challenge_retrieved_at,
			  not_valid_before,
	          not_valid_after,
			  type,
			  ca_name,
			  serial
            )
            VALUES %s
            ON DUPLICATE KEY UPDATE
              challenge_retrieved_at = VALUES(challenge_retrieved_at),
			  not_valid_before = VALUES(not_valid_before),
			  not_valid_after = VALUES(not_valid_after),
			  type = VALUES(type),
			  ca_name = VALUES(ca_name),
			  serial = VALUES(serial)`,
			strings.TrimSuffix(valuePart, ","),
		)

		_, err := ds.writer(ctx).ExecContext(ctx, stmt, args...)
		return err
	}

	generateValueArgs := func(p *fleet.MDMManagedCertificate) (string, []any) {
		valuePart := "(?, ?, ?, ?, ?, ?, ?, ?),"
		args := []any{p.HostUUID, p.ProfileUUID, p.ChallengeRetrievedAt, p.NotValidBefore, p.NotValidAfter, p.Type, p.CAName, p.Serial}
		return valuePart, args
	}

	const defaultBatchSize = 1000
	batchSize := defaultBatchSize
	if ds.testUpsertMDMDesiredProfilesBatchSize > 0 {
		batchSize = ds.testUpsertMDMDesiredProfilesBatchSize
	}

	if err := batchProcessDB(payload, batchSize, generateValueArgs, executeUpsertBatch); err != nil {
		return err
	}

	return nil
}

func (ds *Datastore) ListHostMDMManagedCertificates(ctx context.Context, hostUUID string) ([]*fleet.MDMManagedCertificate, error) {
	hostCertsToRenew := []*fleet.MDMManagedCertificate{}
	err := sqlx.SelectContext(ctx, ds.reader(ctx), &hostCertsToRenew, `
	SELECT profile_uuid, host_uuid, challenge_retrieved_at, not_valid_before, not_valid_after, type, ca_name, serial
	FROM host_mdm_managed_certificates
	WHERE host_uuid = ?
	`, hostUUID)
	return hostCertsToRenew, ctxerr.Wrap(ctx, err, "get mdm managed certificates for host")
}
